home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / sml_nj / 93src.lha / src / runtime / mac / os_mac.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-09  |  70.7 KB  |  2,639 lines

  1. /* os_mac.c
  2.  * 12Sep92  e  adapted from the file of the same name in the Gambit Project
  3.  * Macintosh specific stuff (for THINK C 5.0.1 compiler).
  4.  * portions Copyright ⌐ 1992 Marc Feeley and Douglas H. Currie, Jr.
  5.  */
  6.  
  7. #include <MacHeaders>
  8.  
  9. #include "os_mac.h"
  10. #include <stdio.h>
  11. #include <errno.h>
  12. #include <signal.h>
  13.  
  14. #define use_MacTraps2 (1)
  15.  
  16. /*---------------------------------------------------------------------------*/
  17.  
  18. /* new stuff  29Dec92  e  */
  19.  
  20. #include <GestaltEqu.h>
  21. #include <AppleEvents.h>
  22.  
  23. /* 1Feb93  e */
  24. #ifdef THINK_C
  25. #undef kAERestart
  26. #undef kAEShutDown
  27. #endif
  28. #include <AERegistry.h>
  29.  
  30. static void init_ae();
  31.  
  32. Boolean        gDoQuit = false;
  33. Boolean        gHasAppleEvents = false;
  34. Boolean        gPrintPage = false;
  35. Boolean        spareB1;
  36.  
  37. #include "eventchk.h"        /* 25Jan93  e */
  38. long next_eventchk_ticks;    /* 25Jan93  e */
  39.  
  40. /*---------------------------------------------------------------------------*/
  41.  
  42. TextStyle prefStylNormal =
  43. { monaco, 0, 0, FontSize, { 65536, 65536, 65536 } /* RGBColor Black */ };
  44. TextStyle prefStylHilite =
  45. { monaco, 0, 0, FontSize, { 65536, 65536, 65536 } /* RGBColor Black */ };
  46.  
  47. short prefTabs = dfltTabs;
  48. short prefWrap = dfltWrap;
  49. short prefAutoInd = dfltAutoInd;
  50.  
  51. short current_menus;
  52.  
  53. MenuHandle menus[7];        /* 10Jan93  e */
  54.  
  55. Cursor watch_cursor;
  56. Cursor gc_cursor;
  57. Cursor ibeam_cursor;
  58. Cursor *current_cursor;
  59.  
  60. unsigned char *find_string, *replace_string;
  61.  
  62. Boolean find_ci   = FALSE;
  63. Boolean find_wrap = FALSE;
  64.  
  65. static Boolean smKeyBdP;
  66. static Boolean showPosnP;    /* 10Jan93  e */
  67.  
  68. short interaction_id = 0;
  69. short abnormal_exit = 0;
  70. short interrupted = 0;
  71. short current_volume = 0;
  72.  
  73. static struct {
  74.   short in_use;
  75.   short bold_input;
  76.   WindowPtr wptr;
  77.   ControlHandle vscroll;
  78.   ControlHandle hscroll;
  79.   TeHANDLE hTE;
  80.   short height;
  81.   short dirty;
  82.   short pos, len;
  83.   char *buf;
  84.   Handle out_buf;
  85.   short out_len;
  86.   short is_file;
  87.   unsigned char *filename;
  88.   long needs_inval_ticks;            /* 10Jan93  e --  display of caret position */
  89.   } wind_table[MAX_NB_WINDOWS];
  90.  
  91. static void io_err( short io );
  92.  
  93. #if 0
  94.  
  95. static struct
  96. { char   *a5;
  97.   VBLTask task;
  98. } et;
  99.  
  100. static void intr_task()
  101. { asm
  102.   { move.l a5,-(sp)
  103.     move.l -4(a0),a5
  104.     
  105.     cmpa.l 0x904,a5
  106.     beq.s @goon
  107.     _Debugger
  108. goon:
  109.   }
  110.   if (intr_task_interval > 0)
  111.   { timer_action( 0L, 0L, 1L );
  112.     et.task.vblCount = intr_task_interval;
  113.   }
  114.   else
  115.     et.task.vblCount = 1;
  116.   asm
  117.   { move.l (sp)+,a5
  118.   }
  119. }
  120.  
  121. static void start_intr_task()
  122. { asm
  123.   { move.l a5,et.a5
  124.   }
  125.   et.task.qType    = vType;
  126.   et.task.vblAddr  = (ProcPtr)intr_task;
  127.   et.task.vblCount = 1;
  128.   et.task.vblPhase = 0;
  129.   intr_task_installed = (VInstall( (QElemPtr )&et.task ) == noErr);
  130. }
  131.  
  132. static void stop_intr_task()
  133. { if (intr_task_installed)
  134.   { VRemove( (QElemPtr )&et.task ); intr_task_installed = 0; }
  135. }
  136.  
  137. #endif
  138.  
  139. RgnHandle gCursorRgn;
  140. Boolean gHasWNE = true;
  141. Boolean gHasHWPriv = true;
  142. Boolean gCursRgnOK = false;
  143. Boolean gInBackground = false;
  144. long gWaitTicksBG = 5; /* in ticks,  should be 1..15 */
  145. long gWaitTicksFG = 1; /* in ticks,  should be 1..15 */
  146. /** Define trap numbers **/
  147. #ifndef _Unimplemented
  148. #define _Unimplemented 0xA89F /* Unimplemented trap */
  149. #endif
  150. #ifndef _WaitNextEvent
  151. #define _WaitNextEvent 0xA860 /* WaitNextEvent trap */
  152. #endif
  153. #ifndef _HWPriv
  154. #define _HWPriv 0xA098 /* HWPriv trap */
  155. #endif
  156.  
  157. TrapType GetTrapType(short theTrap)
  158. { /* OS traps start with A0, Tool with A8 or AA. */
  159.   if ((theTrap & 0x0800) == 0)
  160.     return (OSTrap);
  161.   else
  162.     return (ToolTrap);
  163. }
  164. short NumToolboxTraps(void)
  165. { /* InitGraf (trap $A86E) is always implemented. */
  166.   if (NGetTrapAddress(0xA86E, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
  167.     return (0x200);
  168.   else
  169.     return (0x400);
  170. }
  171. Boolean TrapExists(short theTrap)
  172. { TrapType theTrapType;
  173.   theTrapType = GetTrapType(theTrap);
  174.   if ((theTrapType == ToolTrap) && ((theTrap &= 0x07FF) >= NumToolboxTraps()))
  175.     theTrap = _Unimplemented;
  176.   return (NGetTrapAddress(_Unimplemented, ToolTrap) != NGetTrapAddress(theTrap, theTrapType));
  177. }
  178.  
  179. static void setup_cursors()
  180. { CursHandle hCurs;
  181.   hCurs = GetCursor(watchCursor);
  182.   watch_cursor = **hCurs;
  183.   /* 28Jan93  e
  184.   hCurs = GetCursor(gc_cursorID);
  185.   gc_cursor = **hCurs;
  186.   */
  187.   hCurs = GetCursor(iBeamCursor);
  188.   ibeam_cursor = **hCurs;
  189.  
  190.   current_cursor = &watch_cursor;
  191. }
  192.  
  193. /* 02Oct92  e  added ParamText1 */
  194.  
  195. static void ParamText1( Str255 text )
  196. {
  197.     ParamText( text, "\p", "\p", "\p" );
  198. }
  199.  
  200. static void c_to_p( c_str, p_str )
  201. char *c_str;
  202. Str255 p_str;
  203. { short i = 0;
  204.   while (c_str[i] != '\0') { p_str[i+1] = c_str[i]; i++; }
  205.   p_str[0] = i;
  206. }
  207.  
  208. static void p_to_p( p1, p2 )
  209. Str255 p1, p2;
  210. { short len = (unsigned char)*p1++;
  211.   *p2++ = len;
  212.   while (len>0) { *p2++ = *p1++; len--; }
  213. }
  214.  
  215. static void buf_to_p( unsigned short len, char *p1, Str255 p2 )
  216. { if( len > 255 ) len = 255;
  217.   *p2++ = len;
  218.   while (len>0) { *p2++ = *p1++; len--; }
  219. }
  220.  
  221. static void p_to_c( p_str, c_str )
  222. Str255 p_str;
  223. char *c_str;
  224. { short len = (unsigned char)*p_str++, i = 0;
  225.   while (i<len) { *c_str++ = *p_str++; i++; }
  226.   *c_str++ = '\0';
  227. }
  228.  
  229. static short compare_p_to_p( p1, p2 )
  230. Str255 p1, p2;
  231. { short len1 = (unsigned char)*p1++, len2 = (unsigned char)*p2++;
  232.   if (len1 < len2) return -1;
  233.   if (len1 > len2) return 1;
  234.   while (len1>0)
  235.   { short c1 = (unsigned char)*p1++, c2 = (unsigned char)*p2++;
  236.     if (c1 < c2) return -1;
  237.     if (c1 > c2) return 1;
  238.     len1--;
  239.   }
  240.   return 0;
  241. }
  242.  
  243. static void pathstr_to_filename( register Str255 p_str, Str255 f_str )
  244. {    register short plen = p_str[0];
  245.     while( plen && p_str[plen] != ':' ) plen--;
  246.     buf_to_p( p_str[0] - plen, (char *)&p_str[plen+1], f_str );
  247. }
  248.  
  249. /* *** preferences saved to disk *** */
  250.  
  251. #ifdef use_MacTraps2
  252.  
  253. static OSErr findPrefFolder( short *foundVRefNum, long *foundDirID )
  254. {    
  255.   *foundVRefNum = 0;
  256.   *foundDirID = 0;
  257.   /* MacTraps2 has FindFolder() glue */
  258.   return FindFolder( kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
  259.                        foundVRefNum, foundDirID );
  260. }
  261.  
  262. #else
  263.  
  264. #include <GestaltEqu.h>
  265.  
  266. #define BTstQ(arg, bitnbr)        (arg & (1 << bitnbr))
  267.  
  268. static OSErr findPrefFolder( short *foundVRefNum, long *foundDirID )
  269. {
  270.   long          gesResponse;
  271.   SysEnvRec     envRec;
  272.   WDPBRec       myWDPB;
  273.   unsigned char volName[34];
  274.   OSErr         err;
  275.     
  276.   *foundVRefNum = 0;
  277.   *foundDirID = 0;
  278.   if ( !Gestalt( gestaltFindFolderAttr, &gesResponse ) 
  279.           && BTstQ( gesResponse, gestaltFindFolderPresent ) )
  280.   { /* Folder Manager exists */
  281.     err = FindFolder( kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
  282.                        foundVRefNum, foundDirID );
  283.   }
  284.   else
  285.   { /* Gestalt can't give us the answer, so we resort to SysEnvirons */
  286.     if ( !(err = SysEnvirons( curSysEnvVers, &envRec )) )
  287.     {  myWDPB.ioVRefNum = envRec.sysVRefNum;
  288.        volName[0] = '\000';                   /* Zero volume name */
  289.        myWDPB.ioNamePtr = volName;
  290.        myWDPB.ioWDIndex = 0;
  291.        myWDPB.ioWDProcID = 0;
  292.        if ( !(err = PBGetWDInfo( &myWDPB, 0 )) )
  293.        { *foundVRefNum = myWDPB.ioWDVRefNum;
  294.          *foundDirID = myWDPB.ioWDDirID;
  295.        }
  296.     }
  297.   }
  298.   return (err);
  299. }
  300.  
  301. #endif
  302.  
  303. struct prefs
  304. { short version;
  305.   short tabs;
  306.   short wrap;
  307.   Boolean find_ci;
  308.   Boolean find_wrap;
  309.   Boolean spare0;        /* smKeyBdP in Gambit */
  310.   Boolean showPosnP;    /* 10Jan93  e  */
  311.   short spare2;
  312.   short spare3;
  313.   short autoInd;
  314.   TextStyle stylNormal;
  315.   TextStyle stylHilite;
  316.   unsigned char fontnmNormal[64];
  317.   unsigned char fontnmHilite[64];
  318. };
  319.  
  320. void savePrefs( ConstStr255Param fn )
  321. {
  322.     short rRef;
  323.       OSErr err;
  324.     struct prefs **hRes;
  325.     struct prefs  *pRes;
  326.     short foundVRefNum;
  327.     long  foundDirID;
  328.     Str255 fontnmNormal, fontnmHilite;
  329.     
  330.     err = findPrefFolder( &foundVRefNum, &foundDirID );
  331.     if( err != noErr ) return;
  332.     
  333.     if( ( rRef = HOpenResFile( foundVRefNum, foundDirID, fn, fsRdWrPerm ) ) < 0)
  334.     {    HCreateResFile( foundVRefNum, foundDirID, fn );
  335.         { HFileInfo pb;
  336.           pb.ioCompletion = (void *)0;
  337.           pb.ioNamePtr = (StringPtr )fn;
  338.           pb.ioVRefNum = foundVRefNum;
  339.           pb.ioFDirIndex = 0;
  340.           pb.ioDirID = foundDirID;
  341.           err = PBHGetFInfo( &pb, FALSE );
  342.           pb.ioCompletion = (void *)0;
  343.           pb.ioNamePtr = (StringPtr )fn;
  344.           pb.ioVRefNum = foundVRefNum;
  345.           pb.ioFDirIndex = 0;
  346.           pb.ioDirID = foundDirID;
  347.           pb.ioFlFndrInfo.fdCreator = 'NJML'; /* 14Dec92  e  */
  348.           pb.ioFlFndrInfo.fdType    = 'gamP';
  349.           if( err == noErr )
  350.             PBHSetFInfo( &pb, FALSE );
  351.         }
  352.         rRef = HOpenResFile( foundVRefNum, foundDirID, fn, fsRdWrPerm );
  353.     }
  354.     if( rRef < 0 )
  355.         return;
  356.     hRes = (struct prefs **)GetResource('ePrf', 357);
  357.     if(    hRes == 0 || rRef != HomeResFile( (Handle )hRes ) )
  358.     {    hRes = (struct prefs **)NewHandle( sizeof( struct prefs ) );
  359.         if( hRes == 0 )
  360.         {    CloseResFile( rRef );
  361.             return;
  362.         }
  363.         AddResource( (Handle )hRes, (ResType )'ePrf', 357, (ConstStr255Param)"\p" );
  364.         if( ResErr != noErr )
  365.         {    DisposHandle( (Handle )hRes );
  366.             CloseResFile( rRef );
  367.             return;
  368.         }
  369.     }
  370.     pRes = *hRes;
  371.     (*pRes).version    = 1;
  372.     (*pRes).tabs       = prefTabs;
  373.     (*pRes).wrap       = prefWrap;
  374.     (*pRes).find_ci    = find_ci;
  375.     (*pRes).find_wrap  = find_wrap;
  376.     (*pRes).spare0     = 0;
  377.     (*pRes).showPosnP  = showPosnP;        /* 10Jan93  e  */
  378.     (*pRes).spare2     = 0;
  379.     (*pRes).spare3     = 0;
  380.     (*pRes).autoInd    = prefAutoInd;
  381.     (*pRes).stylNormal = prefStylNormal;
  382.     (*pRes).stylHilite = prefStylHilite;
  383.     GetFontName( prefStylNormal.tsFont, fontnmNormal );
  384.     if( fontnmNormal[0] > 63 ) fontnmNormal[0] = 63;
  385.     p_to_p( fontnmNormal, (**hRes).fontnmNormal );
  386.     GetFontName( prefStylHilite.tsFont, fontnmHilite );
  387.     if( fontnmHilite[0] > 63 ) fontnmHilite[0] = 63;
  388.     p_to_p( fontnmHilite, (**hRes).fontnmHilite );
  389.     
  390.     ChangedResource( (Handle )hRes );
  391.     CloseResFile( rRef );
  392. }
  393.  
  394. static void readPrefs( ConstStr255Param fn )
  395. {
  396.     short rRef;
  397.       OSErr err;
  398.     struct prefs **hRes;
  399.     struct prefs  *pRes;
  400.     short foundVRefNum;
  401.     long  foundDirID;
  402.     short    fontNumber;
  403.  
  404.     err = findPrefFolder( &foundVRefNum, &foundDirID );
  405.     if( err != noErr ) return;
  406.     
  407.     rRef = HOpenResFile( foundVRefNum, foundDirID, fn, fsRdWrPerm );
  408.     /* don't test rRef here since resource may come from elsewhere, e.g., from appl. */
  409.     hRes = (struct prefs **)GetResource('ePrf', 357);
  410.     if(    hRes != 0 )
  411.     {    pRes = *hRes;
  412.         if( (*pRes).version == 1 )
  413.         {    prefTabs   = (*pRes).tabs;
  414.             prefWrap   = (*pRes).wrap;
  415.             find_ci    = (*pRes).find_ci;
  416.             find_wrap  = (*pRes).find_wrap;
  417.             prefAutoInd = (*pRes).autoInd;
  418.             showPosnP  = (*pRes).showPosnP;    /* 10Jan93  e  */
  419.             prefStylNormal = (*pRes).stylNormal;
  420.             prefStylHilite = (*pRes).stylHilite;
  421.             GetFNum( (**hRes).fontnmNormal, &prefStylNormal.tsFont );
  422.             if( prefStylNormal.tsFont < 0 ) prefStylNormal.tsFont = 0;
  423.             GetFNum( (**hRes).fontnmHilite, &prefStylHilite.tsFont );
  424.             if( prefStylHilite.tsFont < 0 ) prefStylHilite.tsFont = 0;
  425.         }
  426.     }
  427.     if( rRef >= 0 ) CloseResFile( rRef );
  428. }
  429.  
  430. /* *** */
  431.  
  432. #define fustItem 3
  433. static short itemtowindid[MAX_NB_WINDOWS];
  434. static short windidtodigit[MAX_NB_WINDOWS];
  435. static short qWindItems = 0;
  436.  
  437. typedef struct { short nbmenus6, right, dummy; struct { MenuHandle mh; short left; } menu[100]; } menu_list;
  438.  
  439. static short cmd_key_exists( c )
  440. char c;
  441. {
  442.   menu_list **ml = (menu_list **)MenuList;
  443.   short n = (*ml)->nbmenus6/6;
  444.   short i, j, m, cmd;
  445.   for (i=0; i<n; i++)
  446.   { MenuHandle mh = (*ml)->menu[i].mh;
  447.     m = CountMItems( mh );
  448.     for (j=1; j <= m; j++)
  449.     {
  450.       GetItemCmd( mh, j, &cmd );
  451.       if (cmd == c) return 1;
  452.     }
  453.   }
  454.   return 0;
  455. }
  456.  
  457. static void addWindMenuItem( short id )
  458. {    short d, i, j;
  459.     Str255 title, key = "\p / ";
  460.     WindowPtr wind = wind_table[id].wptr;
  461.     if (qWindItems >= MAX_NB_WINDOWS) return;
  462.     for (d=1; d<10; d++) if (!cmd_key_exists('0'+d)) break;
  463.     if (d < 10) key[3] = '0'+d; else key[2] = ' ';
  464.     windidtodigit[id] = d;
  465.     for (i=0; i < qWindItems; i++)
  466.       if (windidtodigit[itemtowindid[i]] > d) break;
  467.     for (j=qWindItems-1; j > i; j--)
  468.       itemtowindid[j] = itemtowindid[j-1];
  469.     itemtowindid[i] = id;
  470.     GetWTitle( wind, title );
  471.     InsMenuItem( menus[windowsM], key, i+fustItem-1 );
  472.     SetItem( menus[windowsM], i+fustItem, title );
  473.     qWindItems++;
  474. }
  475.  
  476. static void delWindMenuItem( short id )
  477. {    register short i;
  478.     for(i = 0; i < qWindItems; i++)
  479.     {    if( id == itemtowindid[i] )
  480.         {    DelMenuItem( menus[windowsM], i+fustItem );
  481.             for( i++; i < qWindItems; i++ )
  482.                 itemtowindid[i-1] = itemtowindid[i];
  483.             qWindItems--;
  484.             break;
  485.         }
  486.     }
  487. }
  488.  
  489. void eSmudgeWindow( register short w )
  490. {    register short i;
  491.     if( ! wind_table[w].dirty )
  492.     {    wind_table[w].dirty = 1;
  493.         for( i = 0; i < qWindItems; i++ )
  494.         {    if( w == itemtowindid[i] )
  495.             {    SetItemMark( menus[windowsM], i+fustItem, '╫');
  496.                 break;
  497.             }
  498.         }
  499.     }
  500. }
  501.  
  502. void eUnSmudgeWindow( register short w, TeHANDLE hTE )
  503. {    register short i;
  504.     (**hTE).dirty = 0;
  505.     if( wind_table[w].dirty )
  506.     {    wind_table[w].dirty = 0;
  507.         for( i = 0; i < qWindItems; i++ )
  508.         {    if( w == itemtowindid[i] )
  509.             {    SetItemMark( menus[windowsM], i+fustItem, 0);
  510.                 break;
  511.             }
  512.         }
  513.     }
  514. }
  515.  
  516. void eMaybeSmudgeWindow( short w, TeHANDLE hTE )
  517. {
  518.     if( (**hTE).dirty )
  519.         eSmudgeWindow( w );
  520.     else
  521.         eUnSmudgeWindow( w, hTE );    /* for Undo  14Aug92  e  */
  522. }
  523.  
  524. void select_and_show( wptr )
  525. WindowPtr wptr;
  526. {
  527.   SelectWindow( wptr );
  528.   ShowWindow( wptr );
  529. }
  530.  
  531. /* ************* */
  532.  
  533. /* 10Jan93  e  -- separated out Search menu */
  534.  
  535. static void wind_begin()
  536. { short i;
  537.   for (i=0; i<MAX_NB_WINDOWS; i++) wind_table[i].in_use = 0;
  538.   InitGraf( &thePort );
  539.   InitFonts();
  540.   FlushEvents( everyEvent, 0 );
  541.   InitWindows();
  542.   InitMenus();
  543.   TEInit();
  544.   eTeInit();
  545.   InitDialogs( 0L );
  546.   InitCursor();
  547.  
  548.   prefStylHilite.tsFace = bold+condense;
  549.  
  550.   menus[appleM] = GetMenu( appleID );
  551.   AddResMenu( menus[appleM], 'DRVR' );
  552.   menus[fileM]    = GetMenu( fileID );
  553.   menus[editM]    = GetMenu( editID );
  554.   menus[findM]    = GetMenu( findID );
  555.   menus[commandM] = GetMenu( commandID );
  556.   menus[windowsM] = GetMenu( windowsID );
  557.  
  558.   ClearMenuBar();
  559.   for ( (i=appleM); (i<=windowsM); i++ ) InsertMenu(menus[i], 0);
  560.   DrawMenuBar();
  561.   current_menus = 0;
  562.  
  563.   setup_cursors();
  564.  
  565.   find_string =    (unsigned char *)NewPtr( 256 );
  566.   replace_string = (unsigned char *)NewPtr( 256 );
  567.   if( find_string == NULL || replace_string == NULL )
  568.   {    SysBeep(10);
  569.       os_quit();
  570.   }
  571.   find_string[0] = '\0';
  572.   replace_string[0] = '\0';
  573.  
  574.   gCursorRgn = NewRgn();
  575.   SetRectRgn(gCursorRgn, -32768, -32768, 32766, 32766);
  576.   gHasWNE = TrapExists(_WaitNextEvent);
  577.  
  578.   gHasHWPriv = TrapExists(_HWPriv);
  579.  
  580.   readPrefs( PREFS_FILENAME );
  581.  
  582.   init_ae();    /* 29Dec92  e  */
  583. }
  584.  
  585. static void wind_close( id )
  586. short id;
  587. { TeHANDLE hTE = wind_table[id].hTE;
  588.   if (id == interaction_id)
  589.   { HideWindow( wind_table[id].wptr );
  590.     eTeSetSelect( hTE, 0, eTeTextLength( hTE ));
  591.     eTeDelete( hTE );
  592.   }
  593.   else if (wind_table[id].in_use)
  594.   { wind_table[id].in_use = 0;
  595.     HideWindow( wind_table[id].wptr );
  596.     eTeDispose( hTE );
  597.     delWindMenuItem( id );
  598.     DisposeControl( wind_table[id].vscroll );
  599.     DisposeControl( wind_table[id].hscroll );
  600.     DisposeWindow( wind_table[id].wptr );
  601.     if (wind_table[id].buf != NULL)
  602.     { DisposPtr( wind_table[id].buf ); wind_table[id].buf = NULL; }
  603.     if( wind_table[id].out_buf != NULL )
  604.     { DisposHandle( wind_table[id].out_buf ); wind_table[id].out_buf = NULL; }
  605.     if( wind_table[id].filename != NULL )
  606.     { DisposPtr( wind_table[id].filename ); wind_table[id].filename = NULL; }
  607.   }
  608. }
  609.  
  610. static void wind_end()
  611. { short id;
  612.   for (id=MAX_NB_WINDOWS-1; id>=0; id--) wind_close( id );
  613.   eTePutScrap();    /* 27Jan93  e */
  614. }
  615.  
  616. static pascal click_scroll();
  617.  
  618. static short wind_open( name, visible, goaway, bold_input )
  619. char *name;
  620. short visible, goaway, bold_input;
  621. { Rect viewRect, vScrollRect, bounds;
  622.   short width = 80 /*(screenBits.bounds.right-SBarWidth-2*Border-11)/FontW*/;
  623.   short height;
  624.   short id;
  625.   Str255 wname;
  626.  
  627.   for (id=0; id<MAX_NB_WINDOWS; id++) if (!wind_table[id].in_use) break;
  628.   if (id == MAX_NB_WINDOWS) return -1;
  629.  
  630.   height = (screenBits.bounds.bottom-Border-48-SBarWidth)/FontH - id;
  631.  
  632.   bounds.left   = 3 + id*5;
  633.   bounds.right  = bounds.left + width*FontW + SBarWidth + Border;
  634.   bounds.top    = 41 + id*(FontH+3);
  635.   bounds.bottom = bounds.top + height*FontH + SBarWidth + Border;
  636.  
  637.   c_to_p( name, wname );
  638.  
  639.   wind_table[id].wptr = (WindowPtr )
  640.     NewWindow( NULL, &bounds, wname, visible, documentProc, (WindowPtr)-1L, goaway, 0L );
  641.   if (wind_table[id].wptr == NULL) return -1;
  642.  
  643.   SetPort( wind_table[id].wptr );
  644.   TextFont( prefStylNormal.tsFont );
  645.   TextSize( prefStylNormal.tsSize );
  646.  
  647.   vScrollRect = (*wind_table[id].wptr).portRect;
  648.   vScrollRect.left = vScrollRect.right-SBarWidth;
  649.   vScrollRect.right += 1;
  650.   vScrollRect.bottom -= SBarWidth-1;
  651.   vScrollRect.top -= 1;
  652.  
  653.   wind_table[id].vscroll =
  654.     NewControl( wind_table[id].wptr, &vScrollRect, "\p", 1, 0, 0, 0,
  655.                 scrollBarProc, 0L);
  656.  
  657.   if (wind_table[id].vscroll != NULL)
  658.   { static FontInfo fInfo;
  659.  
  660.     vScrollRect = (*wind_table[id].wptr).portRect;
  661.     vScrollRect.top = vScrollRect.bottom-SBarWidth;
  662.     vScrollRect.bottom += 1;
  663.     vScrollRect.left += (vScrollRect.right-vScrollRect.left)>>1;
  664.     vScrollRect.right -= SBarWidth-1;
  665.     wind_table[id].hscroll =
  666.       NewControl( wind_table[id].wptr, &vScrollRect, "\p", 1, 0, 0, 0,
  667.                 scrollBarProc, 0L);
  668.     if (wind_table[id].hscroll != NULL)
  669.     {
  670.  
  671.       viewRect = (*wind_table[id].wptr).portRect;
  672.       viewRect.top    += Border;
  673.       viewRect.left   += Border;
  674.       viewRect.bottom -= SBarWidth;
  675.       viewRect.right  -= SBarWidth;
  676.  
  677.       wind_table[id].hTE = eTeNew( wind_table[id].wptr, viewRect, prefTabs, prefWrap,
  678.                                       prefAutoInd, wind_table[id].hscroll, wind_table[id].vscroll );
  679.  
  680.       if (wind_table[id].hTE != NULL)
  681.       {
  682.         eTeSetStyles( wind_table[id].hTE, &prefStylNormal, &prefStylHilite );
  683.         wind_table[id].height     = height;
  684.         wind_table[id].bold_input = bold_input;
  685.         wind_table[id].dirty      = 0;
  686.         wind_table[id].pos        = 0;
  687.         wind_table[id].len        = 0;
  688.         wind_table[id].buf        = NULL;
  689.         wind_table[id].out_buf    = NULL;
  690.         wind_table[id].out_len    = 0;
  691.         wind_table[id].is_file    = 0;
  692.         wind_table[id].filename   = (unsigned char *)NewPtr( FILENAME_LEN );
  693.         if( wind_table[id].filename != NULL )
  694.         { wind_table[id].filename[0] = '\0';
  695.           wind_table[id].in_use   = 1;
  696.           addWindMenuItem( id );
  697.           return id;
  698.         }
  699.         eTeDispose( wind_table[id].hTE );
  700.       }
  701.       DisposeControl( wind_table[id].hscroll );
  702.     }
  703.     DisposeControl( wind_table[id].vscroll );
  704.   }
  705.   DisposeWindow( wind_table[id].wptr );
  706.   return -1;
  707. }
  708.  
  709. static short discard_changes( id )
  710. short id;
  711. { Str255 title;
  712.   GetWTitle( wind_table[id].wptr, title );
  713.   ParamText( "\pDiscard changes to \"", title, "\p\"?", "\p" );
  714.   SysBeep( 10 );
  715.   switch (CautionAlert( ok_cancel_alertID, 0L ))
  716.   { case 3: return 1;
  717.     default: return 0;
  718.   }
  719. }
  720.  
  721. static short mem_full = 0;
  722. static short supress_mem_full_dialog = 0;        /* 27Jan93  e  */
  723.  
  724. pascal long mem_full_err( size )
  725. long size;
  726. { if (mem_full)
  727.   { ParamText1( "\pOut of memory.  The application will exit." );
  728.     SysBeep( 10 );
  729.     StopAlert( ok_alertID, 0L );
  730.     ExitToShell();
  731.   }
  732.   mem_full = 1;
  733.   if ( ! supress_mem_full_dialog )            /* 27Jan93  e  */
  734.   { ParamText1( "\pOut of memory." );
  735.     SysBeep( 10 );
  736.     StopAlert( ok_alertID, 0L );
  737.   }
  738.   return 0;
  739. }
  740.  
  741. static void already_open_err( name )
  742. Str255 name;
  743. { ParamText( "\p\"", name, "\p\"", "\pis already open.  Close it first." );
  744.   SysBeep( 10 );
  745.   StopAlert( ok_alertID, 0L );
  746. }
  747.  
  748. static void path_too_long_err( name )
  749. Str255 name;
  750. { ParamText( "\pPath to file \"", name, "\p\" is too long.", "\p" );
  751.   SysBeep( 10 );
  752.   StopAlert( ok_alertID, 0L );
  753. }
  754.  
  755. static void wind_err()
  756. { ParamText1( "\pCan't open window" );
  757.   SysBeep( 10 );
  758.   StopAlert( ok_alertID, 0L );
  759. }
  760.  
  761. /* 02Oct92  e  added Printer Not Found check, error number displayed for other errors */
  762.  
  763. static void io_err( short io )
  764. { unsigned char errnostr[16];
  765.   switch (io)
  766.   { case wrPermErr    : ParamText1( "\pCan't write file!" ); break;
  767.     case dupFNErr     : ParamText1( "\pDuplicate file name!" ); break;
  768.     case fBsyErr      : ParamText1( "\pFile is busy!" ); break;
  769.     case vLckdErr     : ParamText1( "\pVolume is locked!" ); break;
  770.     case fLckdErr     : ParamText1( "\pFile is locked!" ); break;
  771.     case fnfErr       : ParamText1( "\pFile not found!" ); break;
  772.     case bdNamErr     : ParamText1( "\pBad filename!" ); break;
  773.     case ioErr        : ParamText1( "\pIO transfer error!" ); break;
  774.     case dskFulErr    : ParamText1( "\pDisk full!" ); break;
  775.     case dirFulErr    : ParamText1( "\pDirectory full!" ); break;
  776.     case mFulErr      : ParamText1( "\pFile is too large for memory!" ); break;
  777.                         
  778.     case -4101          : ParamText1( "\pNo printer selected. Use the Chooser." ); break;
  779.     default           : NumToString( io, errnostr );
  780.                         ParamText( "\pIO Error! Mac error number: ", errnostr, "\p", "\p" );
  781.                         break;
  782.   }
  783.   SysBeep( 10 );
  784.   StopAlert( ok_alertID, 0L );
  785. }
  786.  
  787. static void te_limit_err()
  788. { ParamText1( "\pFile unopened due to size limit on buffer (32000 lines)." );
  789.   SysBeep( 10 );
  790.   StopAlert( ok_alertID, 0L );
  791. }
  792.  
  793. static short check_TEWrite( ptr, len, hTE, bold )
  794. char *ptr;
  795. long len;
  796. eTeHandle hTE;
  797. short bold;
  798. {    eTeWrite( hTE, ptr, len, bold );
  799.     if (mem_full) { mem_full = 0; return 1; }
  800.     return 0;
  801. }
  802.  
  803. /* 23Jul92  e  exported for eKeys */
  804. short check_TEInsert( ptr, len, hTE, bold )
  805. char *ptr;
  806. long len;
  807. eTeHandle hTE;
  808. short bold;
  809. {    eTeInsert( hTE, ptr, len, bold );
  810.     if (mem_full) { mem_full = 0; return 1; }
  811.     return 0;
  812. }
  813.  
  814. static short check_TECut( hTE )
  815. eTeHandle hTE;
  816. { eTeCut( hTE );
  817.   if (mem_full) { mem_full = 0; return 1; }
  818.   return 0;
  819. }
  820.  
  821. static short check_TECopy( hTE )
  822. eTeHandle hTE;
  823. { eTeCopy( hTE );
  824.   if (mem_full) { mem_full = 0; return 1; }
  825.   return 0;
  826. }
  827.  
  828. static short check_TEPaste( hTE, bold )
  829. eTeHandle hTE;
  830. short bold;
  831. {     eTePaste( hTE, bold );
  832.     if (mem_full) { mem_full = 0; return 1; }
  833.     return 0;
  834. }
  835.  
  836. static short check_TEKey( c, hTE, bold, event )
  837. char c;
  838. eTeHandle hTE;
  839. short bold;
  840. EventRecord *event;
  841. {    eTeKey( hTE, c, (event->message & keyCodeMask) >> 8, event->modifiers, bold );
  842.     if (mem_full) { mem_full = 0; return 1; }
  843.     return 0;
  844. }
  845.  
  846. short getfullpath( vRefNum, dirID, fName, Path, MaxLength, warn )
  847. short vRefNum;
  848. long dirID;
  849. Str255 fName;
  850. char *Path;
  851. short MaxLength;
  852. short warn;
  853. {
  854.   char *p, *q;
  855.   long len;
  856.   CInfoPBRec block;
  857.   Str255 directoryName;
  858.  
  859.   p = &Path[MaxLength];
  860.   *--p = '\0';
  861.  
  862.   len = (unsigned char)fName[0];
  863.   p -= len;
  864.   if (p < Path) goto too_long;
  865.   BlockMove( &fName[1], p, len );
  866.  
  867.   block.dirInfo.ioNamePtr = directoryName;
  868.   block.dirInfo.ioDrParID = dirID;
  869.  
  870.   do
  871.   { block.dirInfo.ioVRefNum = vRefNum;
  872.     block.dirInfo.ioFDirIndex = -1;
  873.     block.dirInfo.ioDrDirID = block.dirInfo.ioDrParID;
  874.  
  875.     if (PBGetCatInfo( &block, FALSE ) != noErr) return 0;
  876.     *--p = ':';
  877.     len = (unsigned char)directoryName[0];
  878.     p -= len;
  879.     if (p < Path) goto too_long;
  880.     BlockMove( &directoryName[1], p, len );
  881.   } while ( block.dirInfo.ioDrDirID != fsRtDirID );
  882.  
  883.   q = Path;
  884.   while (*p != '\0') *q++ = *p++;
  885.   *q = '\0';
  886.  
  887.   return 1;
  888.  
  889.   too_long:
  890.   if (warn) path_too_long_err( fName );
  891.   return 0;
  892. }
  893.  
  894. /* 3Jul92  e  so I could get rid of MacTraps2 */
  895. #ifdef use_MacTraps2
  896. short getfullpathfromwd( wdRefNum, fName, Path, MaxLength, warn )
  897. long wdRefNum;
  898. Str255 fName;
  899. char *Path;
  900. short MaxLength;
  901. short warn;
  902. {
  903.   short vRefNum;
  904.   long dirID, procID;
  905.  
  906.   if (GetWDInfo( wdRefNum, &vRefNum, &dirID, &procID ) != noErr) return 0;
  907.  
  908.   return getfullpath( vRefNum, dirID, fName, Path, MaxLength, warn );
  909. }
  910. #else
  911. /* pascal OSErr GetWDInfo(short wdRefNum,short *vRefNum,long *dirID,long *procID) */
  912. short getfullpathfromwd( wdRefNum, fName, Path, MaxLength, warn )
  913. long wdRefNum;
  914. Str255 fName;
  915. char *Path;
  916. short MaxLength;
  917. short warn;
  918. {
  919.   WDPBRec myBlock;
  920.  
  921.   myBlock.ioNamePtr = nil;
  922.   myBlock.ioVRefNum = wdRefNum;
  923.   myBlock.ioWDIndex = 0;
  924.   myBlock.ioWDProcID = 0;
  925.   PBGetWDInfo(&myBlock,false);
  926.  
  927.   if ( myBlock.ioResult != noErr ) return 0;
  928.  
  929.   return getfullpath( myBlock.ioWDVRefNum, myBlock.ioWDDirID, fName, Path, MaxLength, warn );
  930. }
  931. #endif
  932.  
  933. short getfullpathfromcurrentvolume( fName, Path, MaxLength, warn )
  934. Str255 fName;
  935. char *Path;
  936. short MaxLength;
  937. short warn;
  938. { return getfullpathfromwd( (long)current_volume, fName, Path, MaxLength, warn );
  939. }
  940.  
  941. static Point SFGwhere = { 90, 82 };
  942. static Point SFPwhere = { 106, 104 };
  943.  
  944. short get_file( prompt, nbtypes, ftypes, path, maxlength )
  945. Str255 prompt;
  946. short nbtypes;
  947. char *ftypes;
  948. char *path;
  949. short maxlength;
  950. {
  951.   SFReply reply;
  952.  
  953.   if (nbtypes == 0) nbtypes = -1;
  954.  
  955.   eTePutScrap();    /* 10Jan93  e */
  956.   SFGetFile( SFGwhere, prompt, 0L, nbtypes, (SFTypeList *)ftypes, 0L, &reply );
  957.   eTeGetScrap();    /* 10Jan93  e */
  958.   if (!reply.good) return 0;
  959.  
  960.   current_volume = reply.vRefNum;
  961.   return getfullpathfromwd( (long)current_volume, (StringPtr)reply.fName, path, maxlength, 1 );
  962. }
  963.  
  964. short put_file( prompt, deflt, path, maxlength )
  965. Str255 prompt;
  966. Str255 deflt;
  967. char *path;
  968. short maxlength;
  969. {
  970.   SFReply reply;
  971.  
  972.   eTePutScrap();    /* 10Jan93  e */
  973.   SFPutFile( SFPwhere, prompt, deflt, 0L, &reply );
  974.   eTeGetScrap();    /* 10Jan93  e */
  975.   if (!reply.good) return 0;
  976.  
  977.   current_volume = reply.vRefNum;
  978.   return getfullpathfromwd( (long)current_volume, (StringPtr)reply.fName, path, maxlength, 1 );
  979. }
  980.  
  981. static short wptr_to_id( w )
  982. WindowPtr w;
  983. { short id;
  984.   for (id=0; id<MAX_NB_WINDOWS; id++)
  985.     if ((wind_table[id].in_use) && (wind_table[id].wptr == (WindowPtr )w)) return id;
  986.   return -1;
  987. }
  988.  
  989. static void setup_view( id )
  990. short id;
  991. { WindowPtr w = wind_table[id].wptr;
  992.   TeHANDLE hTE = wind_table[id].hTE;
  993.   Rect view = w->portRect;
  994.   /*
  995.   view.right -= SBarWidth;
  996.   view.bottom -= SBarWidth;
  997.   InsetRect(&view, Border, Border);                /*  21Jul92  e  */
  998.   view.top    += Border;
  999.   view.left   += Border;
  1000.   view.bottom -= SBarWidth;
  1001.   view.right  -= SBarWidth;
  1002.   eTeNewView( hTE, &view );
  1003. }
  1004.  
  1005. /* 10Jan93  e -- added display of caret position */
  1006. #if 0
  1007. static void content( short id, EventRecord *event )
  1008. { WindowPtr w = wind_table[id].wptr;
  1009.   eTeHandle hTE = wind_table[id].hTE;
  1010.   short cntlCode;
  1011.   ControlHandle theControl;
  1012.  
  1013.   SetPort( w );
  1014.   ClipRect( &w->portRect );
  1015.   GlobalToLocal( &event->where );
  1016.   if ((cntlCode = FindControl( event->where, w, &theControl )) == 0 )
  1017.   { if (PtInRect( event->where, &(**hTE).viewRect ))
  1018.       eTeClick( hTE, event->where, event->modifiers, event->when );
  1019.   }
  1020.   else if (cntlCode == inThumb)
  1021.   { cntlCode = GetCtlValue( theControl );
  1022.     TrackControl( theControl, event->where, 0L );
  1023.     if ( ( cntlCode = GetCtlValue( theControl ) - cntlCode ) != 0 )
  1024.         if( (**theControl).contrlRect.left < (**theControl).contrlRect.top ) /* horizontal? */
  1025.             eTeScroll( hTE, cntlCode, 0, TRUE );
  1026.         else
  1027.             eTeScroll( hTE, 0, cntlCode, TRUE );
  1028.   }
  1029.   else
  1030.     TrackControl( theControl, event->where, (ProcPtr )-1L );
  1031. }
  1032. #else
  1033. static void really_inval_msgrect( short w )
  1034. { GrafPtr port = wind_table[w].wptr;
  1035.   Rect r = port->portRect;
  1036.   r.right -= (( r.right - r.left ) >> 1 ) + SBarWidth + 1;
  1037.   r.top = r.bottom - SBarWidth + 1;
  1038.   SetPort( port );
  1039.   InvalRect( &r );
  1040. }
  1041. static void inval_msgrect( short w )
  1042. { if ( showPosnP ) wind_table[w].needs_inval_ticks = TickCount();
  1043. }
  1044. static void content( short id, EventRecord *event )
  1045. { WindowPtr w = wind_table[id].wptr;
  1046.   eTeHandle hTE = wind_table[id].hTE;
  1047.   short cntlCode;
  1048.   ControlHandle theControl;
  1049.   ChPos oldCaret;
  1050.  
  1051.   SetPort( w );
  1052.   ClipRect( &w->portRect );
  1053.   GlobalToLocal( &event->where );
  1054.   if ((cntlCode = FindControl( event->where, w, &theControl )) == 0 )
  1055.   { if (PtInRect( event->where, &(**hTE).viewRect ))
  1056.     { oldCaret = (**hTE).caretChPos;
  1057.       eTeClick( hTE, event->where, event->modifiers, event->when );
  1058.       if ( *(long *)&oldCaret != *(long *)&(**hTE).caretChPos ) inval_msgrect( id );
  1059.     }
  1060.   }
  1061.   else if (cntlCode == inThumb)
  1062.   { cntlCode = GetCtlValue( theControl );
  1063.     TrackControl( theControl, event->where, 0L );
  1064.     if ( ( cntlCode = GetCtlValue( theControl ) - cntlCode ) != 0 )
  1065.         if( (**theControl).contrlRect.left < (**theControl).contrlRect.top ) /* horizontal? */
  1066.             eTeScroll( hTE, cntlCode, 0, TRUE );
  1067.         else
  1068.             eTeScroll( hTE, 0, cntlCode, TRUE );
  1069.   }
  1070.   else
  1071.     TrackControl( theControl, event->where, (ProcPtr )-1L );
  1072. }
  1073. #endif
  1074. /* 10Jan93  e -- added display of caret position */
  1075. #if 0
  1076. static void update_window( short w )
  1077. { GrafPtr port = wind_table[w].wptr;
  1078.   Rect r = port->portRect;
  1079. #ifdef USE_eTe_debug
  1080.   Str255 tStr;
  1081. #endif
  1082.   r.right -= (( r.right - r.left ) >> 1 ) + SBarWidth + 1;
  1083.   r.top = r.bottom - SBarWidth;
  1084.   SetPort( port );
  1085.   ClipRect( &port->portRect );    /* added for eTe  16Apr92  e  */
  1086.   BeginUpdate( port );
  1087.   EraseRect( &port->portRect );
  1088.   DrawControls( port );
  1089.   DrawGrowIcon( port );
  1090.   EraseRect( &r );
  1091.   MoveTo( r.left, r.top );
  1092.   LineTo( r.right, r.top );
  1093. #ifdef USE_eTe_debug
  1094.   NumToString( eTeTextLength( wind_table[w].hTE ), tStr);
  1095.   MoveTo( r.left + 4, r.bottom - 4 );
  1096.   ClipRect( &r );
  1097.   DrawString( (ConstStr255Param )tStr );
  1098. #endif
  1099.   eTeUpdate( wind_table[w].hTE );
  1100.   EndUpdate( port );
  1101. }
  1102. #else
  1103. static void update_window( short w )
  1104. { GrafPtr port = wind_table[w].wptr;
  1105.   Rect r = port->portRect;
  1106.   Str255 tStr;
  1107.   eTeHandle hTE;
  1108.   r.right -= (( r.right - r.left ) >> 1 ) + SBarWidth + 1;
  1109.   r.top = r.bottom - SBarWidth;
  1110.   SetPort( port );
  1111.   ClipRect( &port->portRect );    /* added for eTe  16Apr92  e  */
  1112.   BeginUpdate( port );
  1113.   EraseRect( &port->portRect );
  1114.   DrawControls( port );
  1115.   DrawGrowIcon( port );
  1116.   EraseRect( &r );
  1117.   MoveTo( r.left, r.top );
  1118.   LineTo( r.right, r.top );
  1119. #ifdef USE_eTe_debug
  1120.   NumToString( eTeTextLength( wind_table[w].hTE ), tStr);
  1121.   MoveTo( r.left + 4, r.bottom - 4 );
  1122.   ClipRect( &r );
  1123.   DrawString( (ConstStr255Param )tStr );
  1124. #else
  1125.   if ( showPosnP )
  1126.   { hTE = wind_table[w].hTE;
  1127.     MoveTo( r.left + 4, r.bottom - 4 );
  1128.     ClipRect( &r );
  1129.     NumToString( (long )(**hTE).caretChPos.v, tStr);
  1130.     DrawString( (ConstStr255Param )tStr );
  1131.     DrawString( "\p:" );
  1132.     NumToString( (long )(**hTE).caretChPos.h, tStr);
  1133.     DrawString( (ConstStr255Param )tStr );
  1134.   }
  1135. #endif
  1136.   eTeUpdate( wind_table[w].hTE );
  1137.   EndUpdate( port );
  1138. }
  1139. #endif
  1140.  
  1141. static void grow_window( id, p )
  1142. short id;
  1143. Point p;
  1144. { WindowPtr w = wind_table[id].wptr;
  1145.   long result;
  1146.   short oScroll;
  1147.   Rect r, oView;
  1148.   
  1149.   SetPort( w );
  1150.  
  1151.   /* 16Sep92  e  increase min size for H scroll bar
  1152.   SetRect(&r, 80, 80, screenBits.bounds.right, screenBits.bounds.bottom); */
  1153.   /* 13Oct92  e  per: bernard@sigi.cs.colorado.edu
  1154.   SetRect(&r, 150, 80, screenBits.bounds.right, screenBits.bounds.bottom); */
  1155.   r = (**GetGrayRgn()).rgnBBox;
  1156.   r.top = 80;
  1157.   r.left = 150;
  1158.   /*  13Oct92  e  */
  1159.   result = GrowWindow( w, p, &r );
  1160.   if (result == 0) return;
  1161.   SizeWindow( w, LoWord(result), HiWord(result), 1);
  1162.  
  1163.   InvalRect(&w->portRect);
  1164.   setup_view( id );
  1165.   HideControl( wind_table[id].vscroll );
  1166.   MoveControl( wind_table[id].vscroll, w->portRect.right - SBarWidth, w->portRect.top-1);
  1167.   SizeControl( wind_table[id].vscroll, SBarWidth+1, w->portRect.bottom - w->portRect.top-(SBarWidth-2));
  1168.   HideControl( wind_table[id].hscroll );
  1169.   MoveControl( wind_table[id].hscroll,
  1170.                   w->portRect.right-((w->portRect.right-w->portRect.left)>>1),
  1171.                   w->portRect.bottom - SBarWidth);
  1172.   SizeControl( wind_table[id].hscroll,
  1173.                   ((w->portRect.right-w->portRect.left)>>1)-(SBarWidth-1),
  1174.                   SBarWidth+1);
  1175.   ShowControl( wind_table[id].hscroll );
  1176.   ValidRect(&(*wind_table[id].hscroll)->contrlRect );
  1177.   ShowControl( wind_table[id].vscroll );
  1178.   ValidRect(&(*wind_table[id].vscroll)->contrlRect );
  1179.   update_window( id );
  1180.   /* dunno (sometimes appropriate, sometimes not)... eTeShowCaret( wind_table[id].hTE ); */
  1181. }
  1182.  
  1183. static void put_input( id, ptr, len, cr, flush, freshline )
  1184. short id;
  1185. char *ptr;
  1186. short len;
  1187. short cr, flush, freshline;
  1188. { if (wind_table[id].in_use)
  1189.   { long len1;
  1190.     register long len2 = (wind_table[id].len - wind_table[id].pos);
  1191.     register char *buf, *p1, *p2;
  1192.     if ((len2 < 0) || flush) len2 = 0;
  1193.     len1 = ((cr)?1:0) + len2 + (long)len;
  1194.     buf = NewPtr( len1 );
  1195.     if (buf == NULL) { SysBeep(10); return; }
  1196.     p1 = buf;
  1197.     p2 = wind_table[id].buf + wind_table[id].pos;
  1198.     while (len2 > 0) { *p1++ = *p2++; len2--; }
  1199.     p2 = ptr;
  1200.     while (len > 0) { *p1++ = *p2++; len--; }
  1201.     if (cr) *p1++ = '\r';
  1202.     if (wind_table[id].buf != NULL) DisposPtr( wind_table[id].buf );
  1203.     wind_table[id].buf = buf;
  1204.     wind_table[id].pos = 0;
  1205.     wind_table[id].len = len1;
  1206.     if (freshline)
  1207.     { eTeHandle hTE = wind_table[id].hTE;
  1208.       if ( (**hTE).caretChPos.h > 0 )
  1209.         check_TEInsert( "\r", 1L, hTE, 0 );
  1210.       (**hTE).writeChPos = (**hTE).caretChPos; /*  9Jul92  e  */
  1211.       eTeShowCaret( hTE );
  1212.     }
  1213.   }
  1214. }
  1215.  
  1216. static void handle_interrupt()
  1217. { interrupted = 1;
  1218.   /* FlushEvents(keyDownMask,0); */
  1219.   /* raise(SIGINT); */
  1220.   /* errno = EINTR; */
  1221. }
  1222.  
  1223. static short open_file( filename, for_output, txt, io )
  1224. Str255 filename;
  1225. short for_output;
  1226. short txt;
  1227. short *io;
  1228. { ioParam pb;
  1229.   fileParam fp;
  1230.   short refnum;
  1231.   short len = (unsigned char)filename[0];
  1232.   short file_existed = 1;
  1233.  
  1234.   pb.ioNamePtr = filename;
  1235.   pb.ioVRefNum = current_volume;
  1236.   pb.ioVersNum = 0;
  1237.   pb.ioPermssn = ((for_output) ? fsRdWrPerm : fsRdPerm);
  1238.   pb.ioMisc = 0;
  1239.  
  1240.   if (for_output)
  1241.   { asm
  1242.     { lea    pb,a0
  1243.       _PBCreate
  1244.     }
  1245.     file_existed = (pb.ioResult == dupFNErr);
  1246.     if ((pb.ioResult != noErr) && !file_existed)
  1247.     { *io = pb.ioResult;  return -1; }
  1248.   }
  1249.   
  1250.   asm
  1251.   { lea    pb,a0
  1252.     _PBOpen
  1253.   }
  1254.   if (pb.ioResult != noErr)
  1255.   { if (for_output)
  1256.       asm
  1257.       { lea    pb,a0
  1258.         _PBDelete
  1259.       }
  1260.     *io = pb.ioResult;
  1261.     return -1;
  1262.   }
  1263.   refnum = pb.ioRefNum;
  1264.   
  1265.   if (!for_output) { *io = noErr; return refnum; }
  1266.  
  1267.   asm
  1268.   { lea    pb,a0
  1269.     _PBSetEOF
  1270.   }
  1271.  
  1272.   if (!file_existed)
  1273.   { fp.ioNamePtr = filename;
  1274.     fp.ioVRefNum = current_volume;
  1275.     fp.ioFVersNum = 0;
  1276.     fp.ioFDirIndex = 0;
  1277.     asm
  1278.     { lea    fp,a0
  1279.       _PBGetFInfo
  1280.       bmi.s  @1
  1281.     }
  1282.     if (txt)
  1283.       fp.ioFlFndrInfo.fdType = 'TEXT';
  1284.     else
  1285.       fp.ioFlFndrInfo.fdType = 'DATA';
  1286.     fp.ioFlFndrInfo.fdCreator = 'NJML';
  1287.     asm
  1288.     { lea    fp,a0
  1289.       _PBSetFInfo
  1290.       @1
  1291.     }
  1292.   }
  1293.  
  1294.   *io = noErr;
  1295.   return refnum;
  1296. }
  1297.  
  1298. static short close_file( refnum, io )
  1299. short refnum;
  1300. short *io;
  1301. { *io = FSClose( refnum );
  1302.   return (*io != noErr);
  1303. }
  1304.  
  1305. static short read_file( id, line, chr )
  1306. short id;
  1307. long line;
  1308. long chr;
  1309. { TeHANDLE hTE = wind_table[id].hTE;
  1310.   short refnum;
  1311.   short io, io2;
  1312.   long pos = 0;
  1313.   short result;
  1314.   Rect r;
  1315.   short beep = 0;
  1316.   short text = 0;
  1317.   long size, count;
  1318.   ChPos chPos;
  1319.   Handle hData;
  1320.   
  1321.   if ( line > 32768 )
  1322.   { te_limit_err();
  1323.     return 0;
  1324.   }
  1325.   chPos.v = (line==0) ? 0 : line-1;
  1326.   chPos.h = (line==0) ? 0 : chr;
  1327.  
  1328.   SelectWindow( wind_table[id].wptr );
  1329.  
  1330.   if (wind_table[id].dirty)
  1331.     if (!discard_changes( id )) return 0;
  1332.  
  1333.   refnum = open_file( wind_table[id].filename, 0, 1, &io );
  1334.   if (refnum == -1)
  1335.   { io_err( io );
  1336.     return 0;
  1337.   }
  1338.  
  1339.   eTeSetTextPtr( hTE, (Ptr )&text, 1L );
  1340.   io = GetEOF(refnum, &size);
  1341.   if( io == noErr )    {
  1342.     if( hData = NewHandle( size + 1 ) )
  1343.     {    HLock( hData );
  1344.         count = size;
  1345.         io = FSRead( refnum, &count, *hData );
  1346.         HUnlock( hData );
  1347.         if( ( io != noErr ) || ( count != size ) )
  1348.         {    DisposHandle( hData );
  1349.             if ( io == noErr ) io = ioErr;
  1350.             /* io_err( io ); will happen */
  1351.             /* added these next lines 7Jul92  e */
  1352.             mem_full = 0;
  1353.               eTeSetTextPtr( hTE, (Ptr )&text, 1L );
  1354.         }
  1355.         else
  1356.         {    ((char *)*hData)[size] = '\0';
  1357.             io = eTeSetTextHandleDetabify( hTE, hData, prefTabs );
  1358.             if ( io == noErr )
  1359.             {   count = eTeChPosToOffset( hTE, chPos );
  1360.                 if ( count > 0 )
  1361.                     eTeSetSelect( hTE, count-1, count );
  1362.                 else
  1363.                     eTeSetSelect( hTE, count, count );
  1364.                 eTeShowCaret( hTE );
  1365.             }
  1366.             else
  1367.             {    DisposHandle( hData );
  1368.                 /* io_err( io ); will happen */
  1369.                 /* added these next lines 7Jul92  e */
  1370.                 mem_full = 0;
  1371.                   eTeSetTextPtr( hTE, (Ptr )&text, 1L );
  1372.             }
  1373.           }
  1374.       }
  1375.       else
  1376.       { mem_full = 0; io = mFulErr; }     /* mem_full = 0; added  7Jul92  e */
  1377.   }
  1378.  
  1379.   if (close_file( refnum, &io2 ) || ((io != eofErr) && (io != noErr)))
  1380.   { if ((io != eofErr) && (io != noErr)) io_err( io ); else io_err( io2 );
  1381.       eSmudgeWindow( id );
  1382.       return 0;
  1383.   }
  1384.   if (io != noErr)
  1385.       eSmudgeWindow( id );
  1386.   else
  1387.       eUnSmudgeWindow( id, hTE );
  1388.   return (io == noErr);
  1389. }
  1390.  
  1391. static void write_file( id )
  1392. short id;
  1393. { TeHANDLE hTE = wind_table[id].hTE;
  1394.   short refnum;
  1395.   short io, io2;
  1396.   long count;
  1397.  
  1398.   refnum = open_file( wind_table[id].filename, 1, 1, &io );
  1399.   if (refnum == -1)
  1400.   { io_err( io );
  1401.     return;
  1402.   }
  1403.  
  1404.   count = eTeTextLength( hTE );
  1405.   io = FSWrite( refnum, &count, *((**hTE).hText) );
  1406.  
  1407.   if (close_file( refnum, &io2 ) || (io != noErr))
  1408.   { if (io != noErr) io_err( io ); else io_err( io2 );
  1409.     return;
  1410.   }
  1411.  
  1412.   eUnSmudgeWindow( id, hTE );
  1413. }
  1414.  
  1415. short edit( name, line, chr )
  1416. char *name;
  1417. long line;
  1418. long chr;
  1419. { short id;
  1420.   Str255 pname;
  1421.   c_to_p( name, pname );
  1422.   if (pname[0] != '\0')
  1423.   { for (id=0; id<MAX_NB_WINDOWS; id++)
  1424.       if (wind_table[id].in_use && wind_table[id].is_file &&
  1425.           (compare_p_to_p( wind_table[id].filename, pname ) == 0)) break;
  1426.   }
  1427.   else
  1428.     id = MAX_NB_WINDOWS;
  1429.  
  1430.   if (id == MAX_NB_WINDOWS) id = wind_open( name, /* 27Jan93 e -- TRUE */ FALSE, TRUE, FALSE );
  1431.   if (id < 0)
  1432.     wind_err();
  1433.   else
  1434.   { wind_table[id].is_file = 1;
  1435.     p_to_p( pname, wind_table[id].filename );
  1436.     supress_mem_full_dialog = 1;        /* 27Jan93  e  */
  1437.     if ( read_file( id, line, chr ) )
  1438.         select_and_show( wind_table[id].wptr );
  1439.     else
  1440.         wind_close( id );
  1441.     supress_mem_full_dialog = 0;        /* 27Jan93  e  */
  1442.   }
  1443.   return id;
  1444. }
  1445.  
  1446. void save_as( id, path )
  1447. short id;
  1448. char *path;
  1449. { Str255 ppath;
  1450.   short i;
  1451.   c_to_p( path, ppath );
  1452.   for (i=0; i<MAX_NB_WINDOWS; i++)
  1453.     if (wind_table[i].in_use && wind_table[i].is_file &&
  1454.         (compare_p_to_p( wind_table[i].filename, ppath ) == 0))
  1455.     { already_open_err( ppath );
  1456.       return;
  1457.     }
  1458.   p_to_p( ppath, wind_table[id].filename );
  1459.   if (wind_table[id].is_file) SetWTitle( wind_table[id].wptr, ppath );
  1460.   if ( id != interaction_id ) /* 28Jan93  e  */
  1461.   { delWindMenuItem( id );
  1462.     addWindMenuItem( id );
  1463.   }
  1464.   write_file( id );
  1465. }
  1466.  
  1467. static void wind_quit()
  1468. { short id;
  1469.   for (id=MAX_NB_WINDOWS-1; id>=0; id--)
  1470.   { if (wind_table[id].in_use && wind_table[id].is_file && wind_table[id].dirty)
  1471.     { if (!discard_changes( id )) return;
  1472.       wind_close( id );
  1473.     }
  1474.   }
  1475.   abnormal_exit = 0;
  1476.   /* os_quit();    29Dec92  e  */
  1477.   gDoQuit = 1;    /* 29Dec92  e  */
  1478. }
  1479.  
  1480. static void handle_close( id )
  1481. short id;
  1482. { if (wind_table[id].is_file)
  1483.   { if ((wind_table[id].dirty) && (!discard_changes( id ))) return;
  1484.     wind_close( id );
  1485.   }
  1486. }
  1487.  
  1488. static char upcase( char c )
  1489. { if( c >= 'a' &&  c <= 'z' ) return c - 0x20;
  1490.   else return c;
  1491. }
  1492. /* 08Jan93  e  -- changed to return Boolean; added test for empty find string */
  1493. Boolean find_next( id )
  1494. short id;
  1495. { TeHANDLE hTE = wind_table[id].hTE;
  1496.   char *txt = *((**hTE).hText);
  1497.   long pos = eTeChPosToOffset( hTE, (**hTE).selActive ? (**hTE).selEnd : (**hTE).caretChPos );
  1498.   register char *start = txt + pos - 1;
  1499.   register short len = (unsigned char)find_string[0];
  1500.   register char *end = txt + eTeTextLength( hTE ) - len;
  1501.   register short i;
  1502.   Boolean again = TRUE;
  1503.   Str255 ci_string;
  1504.   if ( len == 0 ) goto not_found;
  1505.   if( find_ci )
  1506.   { for (i=len; i>0; i--)
  1507.       ci_string[i] = upcase( find_string[i] );
  1508.     /* ci_string[0] = len; -- not used */
  1509.   }
  1510.   find_begin:
  1511.   while (start < end)
  1512.   { if( find_ci )
  1513.     { for (i=len; i>0; i--)
  1514.         if( upcase( start[i] ) != (char )ci_string[i] ) goto next_pos;
  1515.     }
  1516.     else
  1517.     { for (i=len; i>0; i--)
  1518.         if (start[i] != (char )find_string[i]) goto next_pos;
  1519.     }
  1520.     eTeSetSelect( hTE, (long)(start-txt+1), (long)(start-txt+1+len) );
  1521.     return 1;
  1522.     next_pos:
  1523.     start++;
  1524.   }
  1525.   if( find_wrap && again ) 
  1526.   { start = txt;
  1527.     end = start + pos - len;
  1528.     again = FALSE;
  1529.     goto find_begin;
  1530.   }
  1531. not_found:
  1532.   SysBeep(10);
  1533.   return 0;
  1534. }
  1535.  
  1536. void replace_next( id )
  1537. short id;
  1538. { TeHANDLE hTE = wind_table[id].hTE;
  1539.   if ( ! (**hTE).selActive )
  1540.     SysBeep(10);
  1541.   else
  1542.   { long len = (unsigned char)replace_string[0];
  1543.     check_TEInsert( ((char *)replace_string)+1, len, hTE, wind_table[id].bold_input );
  1544.     find_next( id );
  1545.     eTeShowCaret( hTE );
  1546.   }
  1547. }
  1548.  
  1549. /* 08Jan93  e  */
  1550. void replace_all( id )
  1551. short id;
  1552. { TeHANDLE hTE = wind_table[id].hTE;
  1553.   long len = (unsigned char)replace_string[0];
  1554.   
  1555.   if ( (**hTE).selActive )
  1556.   { long pos = eTeChPosToOffset( hTE, (**hTE).selStart );
  1557.     eTeSetSelect( hTE, pos, pos );
  1558.   }
  1559.   while ( find_next( id ) )
  1560.     check_TEInsert( ((char *)replace_string)+1, len, hTE, wind_table[id].bold_input );
  1561.   eTeShowCaret( hTE );
  1562. }
  1563.  
  1564. static void find_dialog( short id )
  1565. { DialogPtr dp;
  1566.   short i, s;
  1567.   Handle h;
  1568.   Rect r;
  1569.   eTePutScrap();                                          /*  13Oct92  e  */
  1570.   ParamText( "\pFind:", "\pReplace with:", "\p", "\p" );
  1571.   dp = GetNewDialog( find_dlogID, 0L, (WindowPtr)-1L );
  1572.   if (dp == NULL) return;
  1573.   GetDItem( dp, 3, &i, &h, &r );
  1574.   SetIText( h, find_string );
  1575.   GetDItem( dp, 5, &i, &h, &r );
  1576.   SetIText( h, replace_string );
  1577.   GetDItem( dp, 7, &i, &h, &r);
  1578.   SetCtlValue( h, find_wrap );
  1579.   GetDItem( dp, 8, &i, &h, &r);
  1580.   SetCtlValue( h, find_ci );
  1581.   SelIText( dp, 3, 0, find_string[0] );
  1582.   SetCursor( &arrow );
  1583.   do
  1584.   { ModalDialog( 0L, &s );
  1585.     switch( s )
  1586.     { case 1:
  1587.         GetDItem( dp, 3, &i, &h, &r );
  1588.         GetIText( h, find_string );
  1589.         GetDItem( dp, 5, &i, &h, &r );
  1590.         GetIText( h, replace_string );
  1591.         GetDItem( dp, 7, &i, &h, &r);
  1592.         find_wrap = GetCtlValue( h );
  1593.         GetDItem( dp, 8, &i, &h, &r);
  1594.         find_ci   = GetCtlValue( h );
  1595.         break;
  1596.       case 7:
  1597.       case 8:
  1598.         GetDItem( dp, s, &i, &h, &r );
  1599.         SetCtlValue( (ControlHandle )h, GetCtlValue( (ControlHandle )h ) ^ 1 );
  1600.         break;
  1601.     }
  1602.   } while( s != 1 && s != 2 );
  1603.   CloseDialog( dp );
  1604.   if( s == 1 ) find_next( id );
  1605.   eTeGetScrap();                                          /*  13Oct92  e  */
  1606. }
  1607.  
  1608. /* 25Sep92  e  added print menu items */
  1609.  
  1610. static void handle_pgsetup( short id )
  1611.   TeHANDLE hTE = wind_table[id].hTE;
  1612.   SetCursor(&qd.arrow);
  1613.   PageSetupDialog( hTE );
  1614. }
  1615.  
  1616. /* 02Oct92  e  added iPrAbort check */
  1617.  
  1618. static void handle_print( short id )
  1619.   OSErr err;
  1620.   TeHANDLE hTE = wind_table[id].hTE;
  1621.   Str255 flnm;
  1622.   
  1623.   SetCursor(&qd.arrow);
  1624.   err = noErr;
  1625.   if ( ! (**hTE).hPrint )
  1626.     err = PageSetupDialog( hTE );
  1627.   if( ! err )
  1628.   {    pathstr_to_filename( wind_table[id].filename, flnm );
  1629.     err = eTePrint( hTE, true, true, flnm );
  1630.     eTePrint( nil, false, false, flnm );
  1631.   }
  1632.   if( err && err != userCanceledErr && err != iPrAbort ) io_err( err );
  1633. }
  1634.  
  1635. static short handle_menu( result, id )
  1636. long result;
  1637. short id;
  1638. { short theItem, theMenu, m, w;
  1639.   MenuHandle mh;
  1640.   WindowPeek wPtr;
  1641.   Str255 name;
  1642.  
  1643.   theItem = LoWord( result );
  1644.   theMenu = HiWord( result );
  1645.   if (theMenu == 0) return 1;
  1646.   mh = GetMHandle( theMenu );
  1647.   for (m=appleM; m<=windowsM; m++) if (menus[m] == mh) break;
  1648.   switch (m)
  1649.   { case appleM:
  1650.       if (theItem == 1)
  1651.       { eDoDialog(0);    /* about */
  1652.       }
  1653.       else if (theItem == 2)
  1654.         ;
  1655.       else
  1656.       { GetItem(menus[appleM], theItem, &name);
  1657.         OpenDeskAcc( &name );
  1658.       }
  1659.       break;
  1660.     case fileM: 
  1661.       switch (theItem)
  1662.       { case newCommand:
  1663.         { short w = wind_open( "Untitled", TRUE, TRUE, FALSE );
  1664.           if (w < 0)
  1665.             wind_err();
  1666.           else
  1667.             wind_table[w].is_file = 1;
  1668.           break;
  1669.         }
  1670.         case openCommand:
  1671.         { short i;
  1672.           for (i=0; i<MAX_NB_WINDOWS; i++) if (!wind_table[i].in_use) break;
  1673.           if (i == MAX_NB_WINDOWS)
  1674.             wind_err();
  1675.           else
  1676.           { char path[FILENAME_LEN];
  1677.             if (get_file( "\p", 1, "TEXT", path, FILENAME_LEN ))
  1678.               edit( path, 0L, 0L );
  1679.           }
  1680.           break;
  1681.         }
  1682.         case closeCommand:
  1683.           if (id >= 0)
  1684.             handle_close( id );
  1685.           break;
  1686.         case saveCommand:
  1687.           if (id >= 0)
  1688.             if (wind_table[id].is_file && (wind_table[id].filename[0] != '\0'))
  1689.             { write_file( id );
  1690.               break;
  1691.             }
  1692.         case saveasCommand:
  1693.           if (id >= 0)
  1694.           { char path[FILENAME_LEN];
  1695.             Str255 flnm;
  1696.             pathstr_to_filename( wind_table[id].filename, flnm );
  1697.             if (put_file( "\pSave as:", flnm, path, FILENAME_LEN ))
  1698.               save_as( id, path );
  1699.           }
  1700.           break;
  1701.         case revertCommand:
  1702.           if (id >= 0)
  1703.             read_file( id, 0L, 0L );
  1704.           break;
  1705.         /* 25Sep92  e  added print menu items */
  1706.         case pgsetupCommand:
  1707.           if (id >= 0)
  1708.             handle_pgsetup( id );
  1709.           break;
  1710.         case printCommand:
  1711.           if (id >= 0)
  1712.             handle_print( id );
  1713.           break;
  1714.         case quitCommand:
  1715.           wind_quit();
  1716.           if (gDoQuit) os_quit(); /* 29Dec92  e  */
  1717.           break;
  1718.       }
  1719.       break;
  1720.     /* 10Jan93  e  -- separated out Search menu */
  1721.     case editM: 
  1722.       if (id < 0)
  1723.         SystemEdit(theItem-1);
  1724.       else
  1725.       { TeHANDLE hTE = wind_table[id].hTE;
  1726.         switch (theItem)
  1727.         { case undoCommand:
  1728.             eTeUndo( hTE );
  1729.             eMaybeSmudgeWindow( id, hTE );
  1730.             break;
  1731.           case cutCommand:
  1732.             check_TECut( hTE );
  1733.             eMaybeSmudgeWindow( id, hTE );
  1734.             break;
  1735.           case copyCommand:
  1736.             check_TECopy( hTE );
  1737.             break;
  1738.           case pasteCommand:
  1739.             check_TEPaste( hTE, wind_table[id].bold_input );
  1740.             eMaybeSmudgeWindow( id, hTE );
  1741.             break;
  1742.           case clearCommand:
  1743.             eTeDelete( hTE );
  1744.             eMaybeSmudgeWindow( id, hTE );
  1745.             break;
  1746.           case selAllCommand:
  1747.             eTeSetSelect( hTE, 0, eTeTextLength( hTE ));
  1748.             break;
  1749.           case stylesCommand:
  1750.             eStyleDlg( hTE );
  1751.               break;
  1752.           case showPosnCommand:    /* 10Jan93  e  */
  1753.               showPosnP ^= 1;
  1754.             CheckItem( menus[editM], showPosnCommand, showPosnP );
  1755.             for (w=0; w<MAX_NB_WINDOWS; w++)
  1756.                 if (wind_table[w].in_use) really_inval_msgrect( w );
  1757.               break;
  1758.           default: ;
  1759.         }
  1760.         eTeShowCaret( hTE );
  1761.       }
  1762.       break;
  1763.     case findM:
  1764.       if (id >= 0)
  1765.       { TeHANDLE hTE = wind_table[id].hTE;
  1766.         switch (theItem)
  1767.         { case findCommand:
  1768.             find_dialog( id );
  1769.             break;
  1770.           case againCommand:
  1771.             find_next( id );
  1772.             break;
  1773.           case replaceCommand:
  1774.             replace_next( id );
  1775.             eMaybeSmudgeWindow( id, hTE );
  1776.             break;
  1777.           case fEnterCommand:
  1778.           { long sel_sta, sel_end, sel_len = 0;
  1779.             if( (**hTE).selActive ) {
  1780.               sel_sta = eTeChPosToOffset( hTE, (**hTE).selStart );
  1781.               sel_end = eTeChPosToOffset( hTE, (**hTE).selEnd );
  1782.               sel_len = sel_end - sel_sta;
  1783.             }
  1784.             if (sel_len > 0)
  1785.             { if( sel_len > 255 ) sel_len = 255;
  1786.               buf_to_p( (unsigned short)sel_len, *((**hTE).hText) + sel_sta, find_string );
  1787.             }
  1788.             else
  1789.               SysBeep( 1 );
  1790.             break;
  1791.           }
  1792.           case replaceAllCommand:    /* 08Jan93  e  */
  1793.             replace_all( id );
  1794.             eMaybeSmudgeWindow( id, hTE );
  1795.             break;
  1796.         }
  1797.         eTeShowCaret( hTE );
  1798.       }
  1799.       break;
  1800.     case commandM: 
  1801.       switch (theItem)
  1802.       { case interruptCommand:
  1803.           HiliteMenu(0);
  1804.           handle_interrupt();
  1805.           return 0;
  1806.         case helpCommand:
  1807.           eDoDialog(1);    /* add help stuff */
  1808.           break;
  1809.         default:
  1810.           break;
  1811.         }
  1812.       break;
  1813.     case windowsM:
  1814.       switch(theItem)
  1815.       { case 1:
  1816.           select_and_show( wind_table[interaction_id].wptr );
  1817.           break;
  1818.         case 2: /* blank line */
  1819.           break;
  1820.         default:
  1821.           theItem -= fustItem;
  1822.           if(theItem < qWindItems)
  1823.             SelectWindow( wind_table[itemtowindid[theItem]].wptr );
  1824.           break;
  1825.       }
  1826.       break;
  1827.    }
  1828.   HiliteMenu(0);
  1829.   return 1;
  1830. }
  1831.  
  1832. static short do_tasks()
  1833. { short w;
  1834.   register short i;
  1835.   short men;
  1836.   EventRecord event;
  1837.   Rect r;
  1838.   RgnHandle rgn;
  1839.   long ticks = Ticks;
  1840.  
  1841.   for (i=0; i<MAX_NB_WINDOWS; i++)
  1842.     if (wind_table[i].in_use)
  1843.     { if (wind_table[i].out_len > 0)
  1844.       { HLock( wind_table[i].out_buf );
  1845.         check_TEWrite( *wind_table[i].out_buf, (long)wind_table[i].out_len, wind_table[i].hTE, 0 );
  1846.         HUnlock( wind_table[i].out_buf );
  1847.         wind_table[i].out_len = 0;
  1848.       }
  1849.       /* 10Jan93  e -- added display of caret position */
  1850.       if ( wind_table[i].needs_inval_ticks != 0
  1851.            && ( wind_table[i].needs_inval_ticks + 15 ) < ticks )
  1852.       { really_inval_msgrect( i );
  1853.         wind_table[i].needs_inval_ticks = 0;
  1854.       }
  1855.     }
  1856.   w = wptr_to_id( FrontWindow() );
  1857.   if ( (!gInBackground) && (w >= 0) )
  1858.   { Point pt;
  1859.     Cursor *curs;
  1860.     OSEventAvail(0L, &event); /* This returns a NULL event with the global mouse location */
  1861.     if( gCursRgnOK && PtInRgn( event.where, gCursorRgn ) )
  1862.     { /* punt... SetCursor( current_cursor ); */
  1863.     }
  1864.     else
  1865.     { SetPort( (GrafPtr)wind_table[w].wptr );
  1866.       r = (**wind_table[w].hTE).viewRect;
  1867.       LocalToGlobal((Point *)&(r.top));      /* topLeft  */
  1868.       LocalToGlobal((Point *)&(r.bottom));   /* botRight */
  1869.       if (PtInRect( event.where, &r ))
  1870.       { curs = &ibeam_cursor;
  1871.         RectRgn(gCursorRgn, &r);
  1872.       }
  1873.       else
  1874.       { curs = &arrow;
  1875.         SetRectRgn(gCursorRgn, -32768, -32768, 32766, 32766);
  1876.         rgn = NewRgn();
  1877.         RectRgn(rgn, &r);
  1878.         DiffRgn(gCursorRgn, rgn, gCursorRgn);
  1879.         DisposeRgn(rgn);
  1880.       }
  1881.       if (!gCursRgnOK || current_cursor != curs)
  1882.       { current_cursor = curs;
  1883.         SetCursor( current_cursor );
  1884.       }
  1885.       gCursRgnOK = true;
  1886.     }
  1887.     eTeIdle( wind_table[w].hTE );
  1888.     men = (wind_table[w].is_file && (wind_table[w].filename[0] != '\0')) ? 1 : 0;
  1889.   }
  1890.   else
  1891.   { SetRectRgn(gCursorRgn, -32768, -32768, 32766, 32766);
  1892.     gCursRgnOK = false;
  1893.     SetCursor(&qd.arrow);    /*  13Oct92  e  */
  1894.     men = 2;
  1895.   }
  1896.  
  1897.   if ( (!gInBackground) && (men != current_menus) )
  1898.   { current_menus = men;
  1899.     switch (men)
  1900.     { case 0:
  1901.       case 1:
  1902.         /*
  1903.         EnableItem( menus[fileM], newCommand );
  1904.         EnableItem( menus[fileM], openCommand );
  1905.         EnableItem( menus[fileM], closeCommand );
  1906.         */
  1907.         EnableItem( menus[fileM], saveCommand );
  1908.         EnableItem( menus[fileM], saveasCommand );
  1909.         if (men == 0)
  1910.           DisableItem( menus[fileM], revertCommand );
  1911.         else
  1912.           EnableItem( menus[fileM], revertCommand );
  1913.         /*
  1914.         EnableItem( menus[fileM], quitCommand );
  1915.         */
  1916.         EnableItem( menus[fileM], pgsetupCommand );
  1917.         EnableItem( menus[fileM], printCommand );
  1918.         EnableItem( menus[editM], selAllCommand );
  1919.         EnableItem( menus[editM], stylesCommand );
  1920.         EnableItem( menus[editM], showPosnCommand );
  1921.         /*
  1922.         EnableItem( menus[findM], findCommand );
  1923.         EnableItem( menus[findM], againCommand );
  1924.         EnableItem( menus[findM], replaceCommand );
  1925.         EnableItem( menus[findM], replaceAllCommand );
  1926.         EnableItem( menus[findM], fEnterCommand ); */
  1927.         EnableItem( menus[findM], 0 );
  1928.         /*
  1929.         EnableItem( menus[commandM], 0 );
  1930.         */
  1931.         DrawMenuBar();
  1932.         break;
  1933.       case 2:
  1934.         /*
  1935.         DisableItem( menus[fileM], newCommand );
  1936.         DisableItem( menus[fileM], openCommand );
  1937.         DisableItem( menus[fileM], closeCommand );
  1938.         */
  1939.         DisableItem( menus[fileM], saveCommand );
  1940.         DisableItem( menus[fileM], saveasCommand );
  1941.         DisableItem( menus[fileM], revertCommand );
  1942.         /*
  1943.         DisableItem( menus[fileM], quitCommand );
  1944.         */
  1945.         DisableItem( menus[fileM], pgsetupCommand );
  1946.         DisableItem( menus[fileM], printCommand );
  1947.         DisableItem( menus[editM], selAllCommand );
  1948.         DisableItem( menus[editM], stylesCommand );
  1949.         DisableItem( menus[editM], showPosnCommand );
  1950.         /*
  1951.         DisableItem( menus[findM], findCommand );
  1952.         DisableItem( menus[findM], againCommand );
  1953.         DisableItem( menus[findM], replaceCommand );
  1954.         DisableItem( menus[findM], replaceAllCommand );
  1955.         DisableItem( menus[findM], fEnterCommand ); */
  1956.         DisableItem( menus[findM], 0 );
  1957.         /*
  1958.         DisableItem( menus[commandM], 0 );
  1959.         */
  1960.         DrawMenuBar();
  1961.         break;
  1962.     }
  1963.   }
  1964.  
  1965.   if ( (!gInBackground) && (w>=0) )
  1966.   { register EvQElPtr q;
  1967.     for (q = (EvQElPtr)EventQueue.qHead; q != NULL; q = (EvQElPtr)q->qLink)
  1968.       if ((q->evtQWhat == keyDown) && ((char)q->evtQMessage == '.') &&
  1969.           (q->evtQModifiers & cmdKey))
  1970.       { while (GetNextEvent(keyDownMask+keyUpMask+autoKeyMask,&event) &&
  1971.                !((event.what == keyDown) && ((event.message & charCodeMask) == '.') &&
  1972.                  ((event.modifiers & cmdKey) != 0) )) ;
  1973.         handle_interrupt();
  1974.         return 0;
  1975.       }
  1976.   }
  1977.   return 1;
  1978. }
  1979.  
  1980. /* from MacDTS */
  1981. #define kDITop                    0x0050        /* kTopLeft - for positioning the Disk */
  1982. #define kDILeft                    0x0070        /*   Initialization dialogs. */
  1983.  
  1984. void handle_activate( WindowPtr wptr, Boolean activep )
  1985. { GrafPtr port;
  1986.   Rect r;
  1987.   short w = wptr_to_id( wptr );
  1988.   if( w >= 0 )
  1989.   { port = wind_table[w].wptr;
  1990.     r = port->portRect;
  1991.     r.left = r.right - (SBarWidth+1);
  1992.     SetPort( port );
  1993.     InvalRect( &r );
  1994.     r = port->portRect;
  1995.     r.top = r.bottom - (SBarWidth+1);
  1996.     InvalRect( &r );
  1997.     if ( activep )
  1998.     { eTeActivate( wind_table[w].hTE );
  1999.       ShowControl( wind_table[w].vscroll );
  2000.       ShowControl( wind_table[w].hscroll );
  2001.     }
  2002.     else
  2003.     { eTeDeactivate( wind_table[w].hTE );
  2004.       HideControl( wind_table[w].vscroll );
  2005.       HideControl( wind_table[w].hscroll );
  2006.     }
  2007.   }
  2008. }
  2009.  
  2010. static short handle_event( event )
  2011. EventRecord *event;
  2012. { register short i;
  2013.   short w;
  2014.   WindowPtr event_window;
  2015.  
  2016.   if (IsDialogEvent( event ))
  2017.   { DialogPtr dp;
  2018.     short item;
  2019.     DialogSelect( event, &dp, &item );
  2020.     return 1;
  2021.   }
  2022.  
  2023.   w = wptr_to_id( FrontWindow() );
  2024.   { switch (event->what)
  2025.     { case mouseDown:
  2026.         gCursRgnOK = false;
  2027.         switch (FindWindow(event->where,&event_window))
  2028.         { case inDesk: 
  2029.             SysBeep( 10 );
  2030.             break;
  2031.           case inGoAway:
  2032.             if ((w = wptr_to_id( event_window )) >= 0)
  2033.               if (TrackGoAway(event_window,event->where)) handle_close( w );
  2034.             break;
  2035.           case inMenuBar:
  2036.           { TeHANDLE hTE = NULL;
  2037.             if( w >= 0) hTE = wind_table[w].hTE;
  2038.             eTeEditMenuUpdate( hTE, menus[editM] );
  2039.             return handle_menu( MenuSelect(event->where), w );
  2040.           }
  2041.           case inSysWindow:
  2042.             SystemClick(event,event_window);
  2043.             break;
  2044.           case inDrag:
  2045.             if ((w = wptr_to_id( event_window )) >= 0)
  2046.               DragWindow(event_window,event->where,&screenBits.bounds);
  2047.             break;
  2048.           case inGrow:
  2049.             if ((w = wptr_to_id( event_window )) >= 0)
  2050.               grow_window( w, event->where );
  2051.             break;
  2052.           case inContent:
  2053.             if (event_window != FrontWindow())
  2054.               SelectWindow(event_window);
  2055.             else 
  2056.               if ((w = wptr_to_id( event_window )) >= 0)
  2057.                 content( w, event );
  2058.             break;
  2059.           default: ;
  2060.         }
  2061.         gLastMouseDown = *event;
  2062.         break;
  2063.       case mouseUp:
  2064.         gLastMouseUp = *event;
  2065.         break;
  2066.       case keyDown:
  2067.       case autoKey:
  2068.         { unsigned char c = event->message & charCodeMask;
  2069.           TeHANDLE hTE = (w>=0)?wind_table[w].hTE:NULL;
  2070.           if ((event->modifiers & cmdKey) != 0)
  2071.           { long res;
  2072.             if (c == '=') c = '+'; else if (c == '/') c = '?';
  2073.             if (hTE != NULL) eTeEditMenuUpdate( hTE, menus[editM] );
  2074.             res = MenuKey( c );
  2075.             if( HiWord( res ) != 0 )
  2076.                 return handle_menu( res, w );
  2077.             if( (hTE != NULL) && (c >= 0) && (c <= 31) )
  2078.             {    check_TEKey( c, hTE, 0, event );
  2079.                 inval_msgrect( w ); /* 10Jan93  e -- added display of caret position */
  2080.             }
  2081.             break;
  2082.           }
  2083.           if (hTE == NULL) break;
  2084.           /*
  2085.           if( ( event->modifiers & controlKey ) != 0 )
  2086.           { eEditCommand( hTE, c, event->modifiers, wind_table[w].bold_input );
  2087.               eMaybeSmudgeWindow( w, hTE );
  2088.               inval_msgrect( w );
  2089.           }
  2090.           */
  2091.           else if( ( c == 127 /* del fwd */ )  || ( c <= 31 ) )
  2092.           { if( ( c == 3 /*enter*/ ) || (( c == '\r' /*cr*/ ) && ((event->modifiers & optionKey) != 0 )))
  2093.             { short id = (wind_table[w].is_file) ? interaction_id : w;
  2094.               long sel_sta;
  2095.               long sel_end;
  2096.               long sel_len;
  2097.               if( (**hTE).selActive ) {
  2098.                   sel_sta = eTeChPosToOffset( hTE, (**hTE).selStart );
  2099.                   sel_end = eTeChPosToOffset( hTE, (**hTE).selEnd );
  2100.               }
  2101.               else
  2102.               { extern void eTeGetRun( eRec **hE, long *sta, long *end );
  2103.                 if ( w == interaction_id )
  2104.                   eTeGetRun( hTE, &sel_sta, &sel_end );
  2105.                 else
  2106.                   sel_end = sel_sta = eTeChPosToOffset( hTE, (**hTE).caretChPos );
  2107.               }
  2108.               eTeSetSelect( hTE, sel_end, sel_end );
  2109.               sel_len = sel_end - sel_sta;
  2110.               HLock((**hTE).hText);
  2111.               if (sel_len > 0)
  2112.                 put_input( id, *((**hTE).hText) + sel_sta, sel_len, 1, 0, 1 );
  2113.               else
  2114.                 put_input( id, NULL, 0, 1, 0, 1 ); /*  not done yet!?  12Sep92  e  */
  2115.               HUnlock((**hTE).hText);
  2116.             }
  2117.             else if (c == 9) /*tab*/
  2118.             { eTabCommand( hTE, event->modifiers, wind_table[w].bold_input );
  2119.               eMaybeSmudgeWindow( w, hTE );
  2120.               inval_msgrect( w ); /* 10Jan93  e -- added display of caret position */
  2121.             }
  2122.             else
  2123.             { check_TEKey( c, hTE, wind_table[w].bold_input, event );
  2124.               if ((c == '\r') && (**hTE).autoInd)
  2125.                 eTabCommand( hTE, optionKey, wind_table[w].bold_input );
  2126.               eMaybeSmudgeWindow( w, hTE );
  2127.               inval_msgrect( w ); /* 10Jan93  e -- added display of caret position */
  2128.               if ( (c=='\r' /*cr*/) || (c=='\b' /*bs*/) ) eTeShowCaret( hTE );
  2129.             }
  2130.           }
  2131.           else
  2132.           { check_TEKey( c, hTE, wind_table[w].bold_input, event );
  2133.             eMaybeSmudgeWindow( w, hTE );
  2134.             inval_msgrect( w ); /* 10Jan93  e -- added display of caret position */
  2135.             eTeShowCaret( hTE );
  2136.           }
  2137.         }
  2138.         break;
  2139.       case activateEvt:
  2140.         gCursRgnOK = false;
  2141.           handle_activate( (WindowPtr)event->message, ((event->modifiers & activeFlag) != 0) );
  2142.         break;
  2143.       case updateEvt: 
  2144.         if ((w = wptr_to_id( (WindowPtr)event->message )) >= 0)
  2145.         { update_window(w);
  2146.         }
  2147.         else
  2148.         { GrafPtr port = (WindowPtr)event->message;
  2149.           SetPort( port );
  2150.           BeginUpdate( port );
  2151.           EndUpdate( port );
  2152.         }
  2153.         break;
  2154.       case osEvt:
  2155.         if( *(char *)(&event->message) == suspendResumeMessage )
  2156.         { gCursRgnOK = false; /* Suspend/resume is also an activate/deactivate. */
  2157.           gInBackground = !(event->message & resumeFlag);
  2158.           if( gInBackground ) eTePutScrap();                  /*  13Aug92  e  */
  2159.           else                  eTeGetScrap();                  /*  13Aug92  e  */
  2160.           handle_activate( FrontWindow(), !gInBackground );
  2161.         }
  2162.         /* punt mouseMovedMessage */
  2163.         break;
  2164.       case diskEvt:
  2165.         gCursRgnOK = false;                     /* It is not a bad idea to at least call */
  2166.         if (HiWord(event->message) != noErr) /* DIBadMount in response to a diskEvt,  */
  2167.         { Point pt;                             /* so that the user can format a floppy. */
  2168.           SetPt( &pt, kDILeft, kDITop );
  2169.           DIBadMount( pt, event->message );
  2170.         }
  2171.         break;
  2172.       /* 29Dec92  e  */
  2173.       case kHighLevelEvent:
  2174.         AEProcessAppleEvent(event);
  2175.         if (gDoQuit) os_quit();
  2176.         break;
  2177.       default: ;
  2178.     }
  2179.   }
  2180.   return 1;
  2181. }
  2182.  
  2183. long os_get_next_event( EventRecord *event )
  2184. { long result = 0;
  2185.   GrafPtr save;
  2186.   GetPort( &save );
  2187.   if (do_tasks())
  2188.   { if (gHasWNE)
  2189.       { result = (long)( gInBackground ? gWaitTicksBG    /* 22Jul92  e   -- added gMaxSleep */
  2190.                                          : (long )( (gWaitTicksFG > gMaxSleep) ? gMaxSleep
  2191.                                                                                 : gWaitTicksFG) );
  2192.       result = WaitNextEvent( everyEvent, event, result, gCursorRgn );
  2193.     }
  2194.     else
  2195.     { SystemTask();
  2196.       result = GetNextEvent( everyEvent, event );
  2197.     }
  2198.   }
  2199.   SetPort( save );
  2200.   return result;
  2201. }
  2202.  
  2203. long os_handle_event( EventRecord *event )
  2204. { long result;
  2205.   GrafPtr save;
  2206.   GetPort( &save );
  2207.   result = handle_event( event );
  2208.   SetPort( save );
  2209.   return result;
  2210. }
  2211.  
  2212. void os_event_check( void )            /* 25Jan93  e  */
  2213. { EventRecord event;
  2214.   os_get_next_event( &event );
  2215.   os_handle_event( &event );
  2216.   next_eventchk_ticks = Ticks + TicksBetweenEventChecks;
  2217. }
  2218.  
  2219. void os_quit()
  2220. { short i;
  2221.   long ticks;
  2222. #if 0
  2223.   stop_intr_task();
  2224.   for (i=MAX_NB_OPEN_FILES-1; i>0; i--) os_file_close( (OS_FILE)i );
  2225.   if (abnormal_exit)
  2226.   { for (i=0; i<3; i++) { SysBeep(3); Delay( 3, &ticks ); }
  2227.     Delay( 60, &ticks );
  2228.   }
  2229. #endif
  2230.   wind_end();
  2231.   /* was: ExitToShell();  for Tricia: */
  2232.   exit(0);
  2233. }
  2234.  
  2235. /* ******* console io ******* */
  2236.  
  2237. #if 0
  2238. void os_flush_caches()
  2239. { if (gHasHWPriv)
  2240.   asm
  2241.   { moveq #1,d0
  2242.     dc.w _HWPriv
  2243.   }
  2244. }
  2245. #endif
  2246.  
  2247. static short main_internal( )
  2248. { short i;
  2249.   MaxApplZone();
  2250.   for (i = 0; i < 10; i++)
  2251.         MoreMasters();
  2252.   /* CouldAlert( ok_alertID ); */
  2253.   SetGrowZone( mem_full_err );
  2254.  
  2255.   wind_begin();
  2256.  
  2257. #if 0
  2258.   GetVol( new_args, ¤t_volume );
  2259.   if (!getfullpathfromcurrentvolume( CurApName, new_args, 256, 0 ))
  2260.     p_to_c( CurApName, new_args );
  2261. #endif
  2262.  
  2263.   SetCursor( current_cursor );
  2264.  
  2265.   ParamText1( "\p" );
  2266.  
  2267. #if 0
  2268.   loading_dp = GetNewDialog( loading_dlogID, 0L, (WindowPtr)-1L );
  2269.   if (loading_dp != NULL) DrawDialog( loading_dp );
  2270. #endif
  2271.  
  2272.   return 0;
  2273. }
  2274.  
  2275. static short console_initialized = 0;
  2276.  
  2277. WindowPeek os_console_new( unsigned char *name )
  2278. { char cname[256];
  2279.   short id;
  2280.   WindowPeek wp;
  2281.   if( !console_initialized )
  2282.   { main_internal();
  2283.     console_initialized = 1;
  2284.   }
  2285.   p_to_c( name, cname );
  2286.   id = wind_open( cname, FALSE, FALSE, TRUE );
  2287.   if( id < 0 ) return (WindowPeek )0;
  2288.   interaction_id = id;
  2289.   delWindMenuItem( interaction_id );
  2290.   wp = (WindowPeek )wind_table[id].wptr;
  2291.   wp->refCon = (long )id;
  2292.   return(wp);
  2293. }
  2294.  
  2295. long os_console_read( WindowPeek wp, unsigned char *ptr, long cnt )
  2296. { long result = 0;
  2297.   GrafPtr save;
  2298.   GetPort( &save );
  2299.   if( cnt > 0 )
  2300.   { register unsigned char *p1 = ptr;
  2301.     short id = wp->refCon;
  2302.     EventRecord event;
  2303.     do
  2304.     { os_get_next_event( &event );
  2305.       os_handle_event( &event );
  2306.       if( interrupted )
  2307.         goto ocr_done;
  2308.       else
  2309.       { register unsigned char *p2 = (unsigned char *)wind_table[id].buf + wind_table[id].pos;
  2310.         register long len = wind_table[id].len - wind_table[id].pos;
  2311.         register short i = 0;
  2312.         if (len > cnt) len = cnt;
  2313.         while ( i < len )
  2314.         { register unsigned char c = p2[i++];
  2315.           if (c == '\r')
  2316.           { c = '\n';
  2317.             len = i; /* to exit inner loop */
  2318.             cnt = i; /* to exit outer loop */
  2319.           }
  2320.           *p1++ = c;
  2321.         }
  2322.         wind_table[id].pos += i;
  2323.         cnt -= i;
  2324.         result += i;
  2325.       }
  2326.     } while( cnt > 0 );
  2327.   }
  2328. ocr_done:
  2329.   SetPort( save );
  2330.   return result;
  2331. }
  2332.  
  2333. long os_console_write( WindowPeek wp, unsigned char *ptr, long cnt)
  2334. { long result = 0;
  2335.   GrafPtr save;
  2336.   short id = (short )wp->refCon;
  2337.   register unsigned char *p1 = ptr, *p2 = ptr+cnt;
  2338.   register short len = wind_table[id].out_len;
  2339.   register unsigned char *p3;
  2340.   if( wind_table[id].out_buf == NULL )
  2341.   { wind_table[id].out_buf = NewHandle( OUT_BUF_LEN );
  2342.     if( wind_table[id].out_buf == NULL )
  2343.     { SysBeep(10);
  2344.       return result;
  2345.     }
  2346.   }
  2347.   HLock( wind_table[id].out_buf );
  2348.   p3 = (unsigned char *)*wind_table[id].out_buf;
  2349.  
  2350.   if (!(wp->visible))
  2351.     select_and_show( wp );
  2352.  
  2353.   GetPort( &save );
  2354.   while( p1 < p2 )
  2355.   { register unsigned char c = *p1++;
  2356.     if (c == '\n') { p3[len++] = '\r'; goto output; }
  2357.     p3[len++] = c;
  2358.     if (len == OUT_BUF_LEN)
  2359.     { output:
  2360.       if( check_TEWrite( (char *)p3, (long)len, wind_table[id].hTE, 0 ) ) goto werror;
  2361.       wind_table[id].out_len = 0;
  2362.       len = 0;
  2363.     }
  2364.   }
  2365.   wind_table[id].out_len = len;
  2366.   result = cnt;
  2367. werror:
  2368.   SetPort( save );
  2369.   HUnlock( wind_table[id].out_buf );
  2370.   return result;
  2371. }
  2372.  
  2373. long os_console_close( WindowPeek wp )
  2374. { long result = 0;
  2375.   GrafPtr save;
  2376.   short id = (short )wp->refCon;
  2377.   GetPort( &save );
  2378.   if( id < 0 )
  2379.     result = -1;
  2380.   else
  2381.     wind_close( id );
  2382.   SetPort( save );
  2383.   return result;
  2384. }
  2385.  
  2386. /*--------------------------------------------------------------------------*/
  2387.  
  2388. /* new stuff  29Dec92  e  */
  2389.  
  2390. /* Used to check for any unread required parameters. Returns true if we
  2391. ** missed at least one. */
  2392.  
  2393. static Boolean    MissedAnyParameters(AppleEvent *message)
  2394. {
  2395.     OSErr        err;
  2396.     DescType    ignoredActualType;
  2397.     AEKeyword    missedKeyword;
  2398.     Size        ignoredActualSize;
  2399.     EventRecord    event;
  2400.  
  2401.     err = AEGetAttributePtr(    /* SEE IF PARAMETERS ARE ALL USED UP.          */
  2402.         message,                /* AppleEvent to check.                          */
  2403.         keyMissedKeywordAttr,    /* Look for unread parameters.                  */
  2404.         typeWildCard,            /* So we can see what type we missed, if any. */
  2405.         &ignoredActualType,        /* What it would have been if not coerced.      */
  2406.         (Ptr)&missedKeyword,    /* Data area.  (Keyword not handled.)          */
  2407.         sizeof(missedKeyword),    /* Size of data area.                          */
  2408.         &ignoredActualSize        /* Actual data size.                          */
  2409.     );
  2410.  
  2411. /* No error means that we found some unused parameters. */
  2412.  
  2413.     if (err == noErr) {
  2414.         event.message = *(long *) &ignoredActualType;
  2415.         event.where = *(Point *) &missedKeyword;
  2416.         err = errAEEventNotHandled;
  2417.     }
  2418.  
  2419. /* errAEDescNotFound means that there are no more parameters.  If we get
  2420. ** an error code other than that, flag it. */
  2421.  
  2422.     return(err != errAEDescNotFound);
  2423. }
  2424.  
  2425. static OSErr    OpenDocEventHandler(AppleEvent *message, AppleEvent *reply, short mode)
  2426. {
  2427.     OSErr        err;
  2428.     OSErr        err2;
  2429.     AEDesc        theDesc;
  2430.     FSSpec        theFSS;
  2431.     short        loop;
  2432.     long        numFilesToOpen;
  2433.     AEKeyword    ignoredKeyWord;
  2434.     DescType    ignoredType;
  2435.     Size        ignoredSize;
  2436.     char path[512];
  2437.     short w;
  2438.     Str255 flnm;
  2439.     FInfo theFInfo;
  2440.  
  2441.     theDesc.dataHandle = nil;
  2442.         /* Make sure disposing of the descriptors is okay in all cases.
  2443.         ** This will not be necessary after 7.0b3, since the calls that
  2444.         ** attempt to create the descriptors will nil automatically
  2445.         ** upon failure. */
  2446.  
  2447.     if ( err = AEGetParamDesc( message, keyDirectObject, typeAEList, &theDesc ) )
  2448.         return(err);
  2449.  
  2450.     if ( ! MissedAnyParameters( message ) ) {
  2451.  
  2452. /* Got all the parameters we need.  Now, go through the direct object,
  2453. ** see what type it is, and parse it up. */
  2454.  
  2455.         err = AECountItems(&theDesc, &numFilesToOpen);
  2456.         if (!err)
  2457.         {    /* We have numFilesToOpen that need opening, as either a window
  2458.             ** or to be printed.  Go to it... */
  2459.  
  2460.             for (loop = 1; ((loop <= numFilesToOpen) && (!err)); ++loop)
  2461.             {    err = AEGetNthPtr(        /* GET NEXT IN THE LIST...         */
  2462.                     &theDesc,            /* List of file names.             */
  2463.                     loop,                /* Item # in the list.             */
  2464.                     typeFSS,            /* Item is of type FSSpec.         */
  2465.                     &ignoredKeyWord,    /* Returned keyword -- we know.  */
  2466.                     &ignoredType,        /* Returned type -- we know.     */
  2467.                     (Ptr)&theFSS,        /* Where to put the FSSpec info. */
  2468.                     sizeof(theFSS),        /* Size of the FSSpec info.         */
  2469.                     &ignoredSize        /* Actual size -- we know.         */
  2470.                 );
  2471.                 if (err) break;
  2472.  
  2473.                 FSpGetFInfo( &theFSS, &theFInfo );
  2474.                 if ( theFInfo.fdType != 'TEXT' )
  2475.                 { SysBeep( 3 );
  2476.                   continue;
  2477.                 }
  2478.                 gPrintPage = mode;
  2479.                     /* Open the window off-screen if we are printing.
  2480.                     ** We use the gPrintPage global to flag this.  Normally, the
  2481.                     ** gPrintPage global is to tell ImageDocument if we are imaging
  2482.                     ** to the window or to paper.  We don't need it for this yet,
  2483.                     ** as we can't image the document until it is opened.  DoNewWindow()
  2484.                     ** uses gPrintPage as a flag to open the window off-screen, but
  2485.                     ** visible, so that PrintMonitor can use the title of the window
  2486.                     ** as the document name that is being printed. */
  2487.                 
  2488.                 if ( getfullpath( theFSS.vRefNum, theFSS.parID, theFSS.name, path, 511, 1 ) )
  2489.                 {    
  2490.                     w = edit( path, 0L, 0L );
  2491.  
  2492.                     if ( gPrintPage && w >= 0 )
  2493.                     {    pathstr_to_filename( wind_table[w].filename, flnm );
  2494.                         err  = eTePrint( wind_table[w].hTE, (mode == 2), (loop == 1), flnm );
  2495.                         mode = 1;    /* No interaction mode (mode == 2) only valid
  2496.                                     ** for the first printed document. */
  2497.                         wind_close( w );
  2498.                     }
  2499.                 }
  2500.                 else err = errAEEventNotHandled;     /* file pathname too long */
  2501.             }
  2502.             if (gPrintPage)
  2503.             {    eTePrint( nil, false, false, flnm ); /* cleanup */
  2504.                 gPrintPage = 0;                      /* back to normal */
  2505.             }
  2506.         }
  2507.     }
  2508.     err2 = AEDisposeDesc(&theDesc);
  2509.     return(err ? err : err2);
  2510. }
  2511.  
  2512. static Boolean install_aehandler( AEEventClass cl, AEEventID id, ProcPtr p )
  2513. { OSErr    err;
  2514.   err = AEInstallEventHandler( cl, id, p, 0L, false );
  2515.   if (err)
  2516.   { io_err(err);
  2517.     return false;
  2518.   }
  2519.   return true;
  2520. }
  2521.  
  2522. static pascal OSErr    DoAEOpenApplication( AppleEvent *message, AppleEvent *reply, long refcon )
  2523. {
  2524.     return(noErr);
  2525. }
  2526.  
  2527. static pascal OSErr    DoAEOpenDocuments( AppleEvent *message, AppleEvent *reply, long refcon )
  2528. {
  2529.     gCursRgnOK = false;
  2530.     return( OpenDocEventHandler( message, reply, 0 ) ); /* 0 means regular open document */
  2531. }
  2532.  
  2533. #define kTimeOutInTicks (60 * 30)    /* 30 second timeout. */
  2534.  
  2535. static pascal OSErr    DoAEPrintDocuments(AppleEvent *message, AppleEvent *reply, long refcon)
  2536. {
  2537.     short                openMode;
  2538.     ProcessSerialNumber    cpsn, fpsn;
  2539.     Boolean                procsSame;
  2540.  
  2541.     gCursRgnOK = false;
  2542.     openMode = 1;
  2543.     if (!AEInteractWithUser(kTimeOutInTicks, nil, nil))
  2544.         ++openMode;
  2545.  
  2546.     GetCurrentProcess(&cpsn);        /* We may have been moved to the front. */
  2547.     GetFrontProcess(&fpsn);
  2548.     SameProcess(&cpsn, &fpsn, &procsSame);
  2549.     gInBackground = !procsSame;
  2550.  
  2551.     return( OpenDocEventHandler( message, reply, openMode ) );
  2552.         /* openMode is either 1 or 2, depending if user interaction is okay. */
  2553. }
  2554.  
  2555. static pascal OSErr    DoAEQuitApplication( AppleEvent *message, AppleEvent *reply, long refcon )
  2556. {
  2557.     gCursRgnOK = false;
  2558.     wind_quit();
  2559.     return( gDoQuit ? noErr : errAEEventNotHandled );
  2560. }
  2561.  
  2562. /* 1Feb93  e  --  DoScript added */
  2563.  
  2564. static OSErr DoScriptAsFile( FSSpec *theFSS )
  2565. {
  2566.     OSErr err = noErr;
  2567.     char  path[512];
  2568.     
  2569.     if( getfullpath( theFSS->vRefNum, theFSS->parID, theFSS->name, path, 511, 1 ) )
  2570.     {
  2571.         put_input( interaction_id, " use \"", 6, 0, 0, 1 );
  2572.         put_input( interaction_id, path, strlen(path), 0, 0, 0 );
  2573.         put_input( interaction_id, "\";", 2, 1, 0, 0 );
  2574.     }
  2575.     else err = errAEEventNotHandled;
  2576.     return err;
  2577. }
  2578.  
  2579. static pascal OSErr DoAEDoScript( AppleEvent *theAEEvent, AppleEvent *theAEReply, long *theRefCon)
  2580. {
  2581.     OSErr        theErr;
  2582.     DescType    typeCode;
  2583.     Size        sizeOfParam, actualSize;
  2584.     char        ourScriptText[256];
  2585.     FSSpec        ourScriptFSpec;
  2586.  
  2587.     /* Get the script to run */ 
  2588.  
  2589.     theErr = AESizeOfParam( theAEEvent, keyDirectObject, &typeCode, &sizeOfParam);
  2590.     if (theErr != noErr)
  2591.     {    /*
  2592.             If we fail here just return the error. We don't need to do any clean up since 
  2593.             we've allocated nothing on the heap yet.  The Apple Event Manager automatically 
  2594.             adds the error number to the reply as keyErrorNumber for non zero handler returns.
  2595.         */
  2596.         return theErr;
  2597.     }
  2598.     else if ((typeCode == typeChar) || (typeCode == typeStyledText) || (typeCode == typeIntlText))
  2599.     {
  2600.         theErr = AEGetParamPtr( theAEEvent, keyDirectObject, typeChar, &typeCode,
  2601.                                  (Ptr)&ourScriptText, sizeof(ourScriptText), &actualSize);
  2602.         if (theErr == noErr)
  2603.             if ( MissedAnyParameters( theAEEvent ) )
  2604.                 theErr = errAEEventNotHandled;
  2605.             else put_input( interaction_id, ourScriptText, actualSize, 1, 0, 1 );
  2606.     }
  2607.     else if (typeCode == typeAlias)
  2608.     {
  2609.         theErr = AEGetParamPtr( theAEEvent, keyDirectObject, typeFSS, &typeCode,
  2610.                                 (Ptr)&ourScriptFSpec, sizeof(ourScriptFSpec), &actualSize);
  2611.         if ( theErr == noErr )
  2612.             if ( MissedAnyParameters( theAEEvent ) )
  2613.                 theErr = errAEEventNotHandled;
  2614.             else theErr = DoScriptAsFile( &ourScriptFSpec );
  2615.     }
  2616.     else theErr = errAEEventNotHandled;
  2617.     return theErr;
  2618. }
  2619.  
  2620.  
  2621. static void init_ae()
  2622. {
  2623.     long    result;
  2624.  
  2625.     gHasAppleEvents = (Gestalt(gestaltAppleEventsAttr, &result) ? false : result != 0);
  2626.  
  2627.     if (gHasAppleEvents)
  2628.          install_aehandler( kCoreEventClass, kAEOpenApplication, (ProcPtr)DoAEOpenApplication )
  2629.       && install_aehandler( kCoreEventClass, kAEOpenDocuments, (ProcPtr)DoAEOpenDocuments )
  2630.       && install_aehandler( kCoreEventClass, kAEPrintDocuments, (ProcPtr)DoAEPrintDocuments )
  2631.       && install_aehandler( kCoreEventClass, kAEQuitApplication, (ProcPtr)DoAEQuitApplication )
  2632.       && install_aehandler( kAEMiscStandards, kAEDoScript, (ProcPtr)DoAEDoScript );
  2633. }
  2634.  
  2635. /*--------------------------------------------------------------------------*/
  2636.  
  2637.